diff --git a/internal/gatewayapi/filters.go b/internal/gatewayapi/filters.go index b3d2ddb4074..aecc2e81131 100644 --- a/internal/gatewayapi/filters.go +++ b/internal/gatewayapi/filters.go @@ -445,7 +445,7 @@ func (t *Translator) processRequestHeaderModifierFilter( newHeader := ir.AddHeader{ Name: headerKey, Append: true, - Value: addHeader.Value, + Value: strings.Split(addHeader.Value, ","), } filterContext.AddRequestHeaders = append(filterContext.AddRequestHeaders, newHeader) @@ -500,7 +500,7 @@ func (t *Translator) processRequestHeaderModifierFilter( newHeader := ir.AddHeader{ Name: string(setHeader.Name), Append: false, - Value: setHeader.Value, + Value: strings.Split(setHeader.Value, ","), } filterContext.AddRequestHeaders = append(filterContext.AddRequestHeaders, newHeader) @@ -617,7 +617,7 @@ func (t *Translator) processResponseHeaderModifierFilter( newHeader := ir.AddHeader{ Name: headerKey, Append: true, - Value: addHeader.Value, + Value: strings.Split(addHeader.Value, ","), } filterContext.AddResponseHeaders = append(filterContext.AddResponseHeaders, newHeader) @@ -672,7 +672,7 @@ func (t *Translator) processResponseHeaderModifierFilter( newHeader := ir.AddHeader{ Name: string(setHeader.Name), Append: false, - Value: setHeader.Value, + Value: strings.Split(setHeader.Value, ","), } filterContext.AddResponseHeaders = append(filterContext.AddResponseHeaders, newHeader) diff --git a/internal/gatewayapi/testdata/grpcroute-with-request-header-modifier.in.yaml b/internal/gatewayapi/testdata/grpcroute-with-request-header-modifier.in.yaml index 2c48dad582e..29fcb5a75a1 100644 --- a/internal/gatewayapi/testdata/grpcroute-with-request-header-modifier.in.yaml +++ b/internal/gatewayapi/testdata/grpcroute-with-request-header-modifier.in.yaml @@ -26,6 +26,11 @@ grpcRoutes: sectionName: http rules: - filters: + - type: "RequestHeaderModifier" + requestHeaderModifier: + add: + - name: "my-header-multi-value" + value: "foo,bar" - type: "RequestHeaderModifier" requestHeaderModifier: add: diff --git a/internal/gatewayapi/testdata/grpcroute-with-request-header-modifier.out.yaml b/internal/gatewayapi/testdata/grpcroute-with-request-header-modifier.out.yaml index f36c9c969cc..110d404c44f 100644 --- a/internal/gatewayapi/testdata/grpcroute-with-request-header-modifier.out.yaml +++ b/internal/gatewayapi/testdata/grpcroute-with-request-header-modifier.out.yaml @@ -56,6 +56,11 @@ grpcRoutes: - name: service-1 port: 8080 filters: + - requestHeaderModifier: + add: + - name: my-header-multi-value + value: foo,bar + type: RequestHeaderModifier - requestHeaderModifier: add: - name: my-header @@ -117,9 +122,15 @@ xdsIR: port: 10080 routes: - addRequestHeaders: + - append: true + name: my-header-multi-value + value: + - foo + - bar - append: true name: my-header - value: foo + value: + - foo destination: name: grpcroute/default/grpcroute-1/rule/0 settings: diff --git a/internal/gatewayapi/testdata/httproute-with-backendref-add-multiple-filters.out.yaml b/internal/gatewayapi/testdata/httproute-with-backendref-add-multiple-filters.out.yaml index 78655fc8476..122d09efdeb 100644 --- a/internal/gatewayapi/testdata/httproute-with-backendref-add-multiple-filters.out.yaml +++ b/internal/gatewayapi/testdata/httproute-with-backendref-add-multiple-filters.out.yaml @@ -147,7 +147,8 @@ xdsIR: addRequestHeaders: - append: false name: add-header-3 - value: some-value + value: + - some-value protocol: HTTP weight: 1 hostname: '*' @@ -172,10 +173,12 @@ xdsIR: addRequestHeaders: - append: true name: add-header-1 - value: some-value + value: + - some-value - append: true name: add-header-2 - value: some-value + value: + - some-value protocol: HTTP weight: 8 - addressType: IP diff --git a/internal/gatewayapi/testdata/httproute-with-header-filter-duplicate-add-multiple-filters.out.yaml b/internal/gatewayapi/testdata/httproute-with-header-filter-duplicate-add-multiple-filters.out.yaml index a86e71b4534..605aa384f3e 100644 --- a/internal/gatewayapi/testdata/httproute-with-header-filter-duplicate-add-multiple-filters.out.yaml +++ b/internal/gatewayapi/testdata/httproute-with-header-filter-duplicate-add-multiple-filters.out.yaml @@ -134,13 +134,16 @@ xdsIR: - addRequestHeaders: - append: true name: add-header-1 - value: some-value + value: + - some-value - append: true name: add-header-2 - value: some-value + value: + - some-value - append: true name: add-header-3 - value: some-value + value: + - some-value destination: name: httproute/default/httproute-1/rule/0 settings: diff --git a/internal/gatewayapi/testdata/httproute-with-header-filter-duplicate-adds.out.yaml b/internal/gatewayapi/testdata/httproute-with-header-filter-duplicate-adds.out.yaml index 39cc44429f6..f122fc17d5b 100644 --- a/internal/gatewayapi/testdata/httproute-with-header-filter-duplicate-adds.out.yaml +++ b/internal/gatewayapi/testdata/httproute-with-header-filter-duplicate-adds.out.yaml @@ -144,19 +144,24 @@ xdsIR: - addRequestHeaders: - append: true name: Set-Header-1 - value: some-value + value: + - some-value - append: true name: set-header-2 - value: some-value + value: + - some-value - append: true name: set-header-3 - value: some-value + value: + - some-value - append: true name: set-header-5 - value: some-value + value: + - some-value - append: false name: set-header-4 - value: some-value + value: + - some-value destination: name: httproute/default/httproute-1/rule/0 settings: diff --git a/internal/gatewayapi/testdata/httproute-with-header-filter-empty-header-values.out.yaml b/internal/gatewayapi/testdata/httproute-with-header-filter-empty-header-values.out.yaml index b3814e2d41d..67c14e133a7 100644 --- a/internal/gatewayapi/testdata/httproute-with-header-filter-empty-header-values.out.yaml +++ b/internal/gatewayapi/testdata/httproute-with-header-filter-empty-header-values.out.yaml @@ -128,10 +128,12 @@ xdsIR: - addRequestHeaders: - append: true name: example-header-2 - value: "" + value: + - "" - append: false name: example-header-1 - value: "" + value: + - "" destination: name: httproute/default/httproute-1/rule/0 settings: diff --git a/internal/gatewayapi/testdata/httproute-with-mirror-filter-multiple.out.yaml b/internal/gatewayapi/testdata/httproute-with-mirror-filter-multiple.out.yaml index 9aa6f0bf23b..c6e534c9c63 100644 --- a/internal/gatewayapi/testdata/httproute-with-mirror-filter-multiple.out.yaml +++ b/internal/gatewayapi/testdata/httproute-with-mirror-filter-multiple.out.yaml @@ -144,13 +144,16 @@ xdsIR: - addRequestHeaders: - append: true name: X-Header-Add - value: header-val-1 + value: + - header-val-1 - append: true name: X-Header-Add-Append - value: header-val-2 + value: + - header-val-2 - append: false name: X-Header-Set - value: set-overwrites-values + value: + - set-overwrites-values destination: name: httproute/default/httproute-1/rule/0 settings: diff --git a/internal/gatewayapi/testdata/httproute-with-response-header-filter-adds.out.yaml b/internal/gatewayapi/testdata/httproute-with-response-header-filter-adds.out.yaml index 7b53542bdfa..6dcb4b28779 100644 --- a/internal/gatewayapi/testdata/httproute-with-response-header-filter-adds.out.yaml +++ b/internal/gatewayapi/testdata/httproute-with-response-header-filter-adds.out.yaml @@ -140,19 +140,24 @@ xdsIR: - addResponseHeaders: - append: true name: Set-Header-1 - value: some-value + value: + - some-value - append: true name: set-header-2 - value: some-value + value: + - some-value - append: true name: set-header-3 - value: some-value + value: + - some-value - append: true name: set-header-5 - value: some-value + value: + - some-value - append: false name: set-header-4 - value: some-value + value: + - some-value destination: name: httproute/default/httproute-1/rule/0 settings: diff --git a/internal/gatewayapi/testdata/httproute-with-response-header-filter-duplicate-add-multiple-filters.out.yaml b/internal/gatewayapi/testdata/httproute-with-response-header-filter-duplicate-add-multiple-filters.out.yaml index 459c4264740..47d61c9fcfa 100644 --- a/internal/gatewayapi/testdata/httproute-with-response-header-filter-duplicate-add-multiple-filters.out.yaml +++ b/internal/gatewayapi/testdata/httproute-with-response-header-filter-duplicate-add-multiple-filters.out.yaml @@ -134,13 +134,16 @@ xdsIR: - addResponseHeaders: - append: true name: add-header-1 - value: some-value + value: + - some-value - append: true name: add-header-2 - value: some-value + value: + - some-value - append: true name: add-header-3 - value: some-value + value: + - some-value destination: name: httproute/default/httproute-1/rule/0 settings: diff --git a/internal/gatewayapi/testdata/httproute-with-response-header-filter-duplicate-adds.out.yaml b/internal/gatewayapi/testdata/httproute-with-response-header-filter-duplicate-adds.out.yaml index d2b4ffbe3f2..1d2f4f7124c 100644 --- a/internal/gatewayapi/testdata/httproute-with-response-header-filter-duplicate-adds.out.yaml +++ b/internal/gatewayapi/testdata/httproute-with-response-header-filter-duplicate-adds.out.yaml @@ -144,19 +144,24 @@ xdsIR: - addResponseHeaders: - append: true name: Set-Header-1 - value: some-value + value: + - some-value - append: true name: set-header-2 - value: some-value + value: + - some-value - append: true name: set-header-3 - value: some-value + value: + - some-value - append: true name: set-header-5 - value: some-value + value: + - some-value - append: false name: set-header-4 - value: some-value + value: + - some-value destination: name: httproute/default/httproute-1/rule/0 settings: diff --git a/internal/gatewayapi/testdata/httproute-with-response-header-filter-empty-header-values.out.yaml b/internal/gatewayapi/testdata/httproute-with-response-header-filter-empty-header-values.out.yaml index 9d188a03dc0..723cabbe6f7 100644 --- a/internal/gatewayapi/testdata/httproute-with-response-header-filter-empty-header-values.out.yaml +++ b/internal/gatewayapi/testdata/httproute-with-response-header-filter-empty-header-values.out.yaml @@ -128,10 +128,12 @@ xdsIR: - addResponseHeaders: - append: true name: example-header-2 - value: "" + value: + - "" - append: false name: example-header-1 - value: "" + value: + - "" destination: name: httproute/default/httproute-1/rule/0 settings: diff --git a/internal/ir/xds.go b/internal/ir/xds.go index 3d300f1a539..68f16439400 100644 --- a/internal/ir/xds.go +++ b/internal/ir/xds.go @@ -1178,9 +1178,9 @@ func NewDestEndpoint(host string, port uint32) *DestinationEndpoint { // AddHeader configures a header to be added to a request or response. // +k8s:deepcopy-gen=true type AddHeader struct { - Name string `json:"name" yaml:"name"` - Value string `json:"value" yaml:"value"` - Append bool `json:"append" yaml:"append"` + Name string `json:"name" yaml:"name"` + Value []string `json:"value" yaml:"value"` + Append bool `json:"append" yaml:"append"` } // Validate the fields within the AddHeader structure diff --git a/internal/ir/xds_test.go b/internal/ir/xds_test.go index 9492c378344..6724549e39f 100644 --- a/internal/ir/xds_test.go +++ b/internal/ir/xds_test.go @@ -338,17 +338,16 @@ var ( AddRequestHeaders: []AddHeader{ { Name: "example-header", - Value: "example-value", + Value: []string{"example-value"}, Append: true, }, { Name: "example-header-2", - Value: "example-value-2", + Value: []string{"example-value-2"}, Append: false, }, { Name: "empty-header", - Value: "", Append: false, }, }, @@ -376,12 +375,12 @@ var ( AddRequestHeaders: []AddHeader{ { Name: "example-header", - Value: "example-value", + Value: []string{"example-value"}, Append: true, }, { Name: "example-header", - Value: "example-value-2", + Value: []string{"example-value-2"}, Append: false, }, }, @@ -401,7 +400,7 @@ var ( AddRequestHeaders: []AddHeader{ { Name: "", - Value: "example-value", + Value: []string{"example-value"}, Append: true, }, }, @@ -416,17 +415,16 @@ var ( AddResponseHeaders: []AddHeader{ { Name: "example-header", - Value: "example-value", + Value: []string{"example-value"}, Append: true, }, { Name: "example-header-2", - Value: "example-value-2", + Value: []string{"example-value-2"}, Append: false, }, { Name: "empty-header", - Value: "", Append: false, }, }, @@ -454,12 +452,12 @@ var ( AddResponseHeaders: []AddHeader{ { Name: "example-header", - Value: "example-value", + Value: []string{"example-value"}, Append: true, }, { Name: "example-header", - Value: "example-value-2", + Value: []string{"example-value-2"}, Append: false, }, }, @@ -479,7 +477,7 @@ var ( AddResponseHeaders: []AddHeader{ { Name: "", - Value: "example-value", + Value: []string{"example-value"}, Append: true, }, }, diff --git a/internal/ir/zz_generated.deepcopy.go b/internal/ir/zz_generated.deepcopy.go index 273eeb1c3ca..3262cf8d721 100644 --- a/internal/ir/zz_generated.deepcopy.go +++ b/internal/ir/zz_generated.deepcopy.go @@ -191,6 +191,11 @@ func (in *ActiveHealthCheck) DeepCopy() *ActiveHealthCheck { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *AddHeader) DeepCopyInto(out *AddHeader) { *out = *in + if in.Value != nil { + in, out := &in.Value, &out.Value + *out = make([]string, len(*in)) + copy(*out, *in) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AddHeader. @@ -588,7 +593,9 @@ func (in *DestinationFilters) DeepCopyInto(out *DestinationFilters) { if in.AddRequestHeaders != nil { in, out := &in.AddRequestHeaders, &out.AddRequestHeaders *out = make([]AddHeader, len(*in)) - copy(*out, *in) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } } if in.RemoveRequestHeaders != nil { in, out := &in.RemoveRequestHeaders, &out.RemoveRequestHeaders @@ -598,7 +605,9 @@ func (in *DestinationFilters) DeepCopyInto(out *DestinationFilters) { if in.AddResponseHeaders != nil { in, out := &in.AddResponseHeaders, &out.AddResponseHeaders *out = make([]AddHeader, len(*in)) - copy(*out, *in) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } } if in.RemoveResponseHeaders != nil { in, out := &in.RemoveResponseHeaders, &out.RemoveResponseHeaders @@ -1234,7 +1243,9 @@ func (in *HTTPRoute) DeepCopyInto(out *HTTPRoute) { if in.AddRequestHeaders != nil { in, out := &in.AddRequestHeaders, &out.AddRequestHeaders *out = make([]AddHeader, len(*in)) - copy(*out, *in) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } } if in.RemoveRequestHeaders != nil { in, out := &in.RemoveRequestHeaders, &out.RemoveRequestHeaders @@ -1244,7 +1255,9 @@ func (in *HTTPRoute) DeepCopyInto(out *HTTPRoute) { if in.AddResponseHeaders != nil { in, out := &in.AddResponseHeaders, &out.AddResponseHeaders *out = make([]AddHeader, len(*in)) - copy(*out, *in) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } } if in.RemoveResponseHeaders != nil { in, out := &in.RemoveResponseHeaders, &out.RemoveResponseHeaders diff --git a/internal/xds/translator/route.go b/internal/xds/translator/route.go index 8a56e9e42b1..6a9e72f498c 100644 --- a/internal/xds/translator/route.go +++ b/internal/xds/translator/route.go @@ -438,9 +438,9 @@ func buildXdsRequestMirrorPolicies(mirrorDestinations []*ir.RouteDestination) [] } func buildXdsAddedHeaders(headersToAdd []ir.AddHeader) []*corev3.HeaderValueOption { - headerValueOptions := make([]*corev3.HeaderValueOption, len(headersToAdd)) + headerValueOptions := []*corev3.HeaderValueOption{} - for i, header := range headersToAdd { + for _, header := range headersToAdd { var appendAction corev3.HeaderValueOption_HeaderAppendAction if header.Append { @@ -448,18 +448,26 @@ func buildXdsAddedHeaders(headersToAdd []ir.AddHeader) []*corev3.HeaderValueOpti } else { appendAction = corev3.HeaderValueOption_OVERWRITE_IF_EXISTS_OR_ADD } - - headerValueOptions[i] = &corev3.HeaderValueOption{ - Header: &corev3.HeaderValue{ - Key: header.Name, - Value: header.Value, - }, - AppendAction: appendAction, - } - // Allow empty headers to be set, but don't add the config to do so unless necessary - if header.Value == "" { - headerValueOptions[i].KeepEmptyValue = true + if len(header.Value) == 0 { + headerValueOptions = append(headerValueOptions, &corev3.HeaderValueOption{ + Header: &corev3.HeaderValue{ + Key: header.Name, + }, + AppendAction: appendAction, + KeepEmptyValue: true, + }) + } else { + for _, val := range header.Value { + headerValueOptions = append(headerValueOptions, &corev3.HeaderValueOption{ + Header: &corev3.HeaderValue{ + Key: header.Name, + Value: val, + }, + AppendAction: appendAction, + KeepEmptyValue: val == "", + }) + } } } diff --git a/internal/xds/translator/testdata/in/xds-ir/http-route-request-headers.yaml b/internal/xds/translator/testdata/in/xds-ir/http-route-request-headers.yaml index c3dc4417dcc..fb45b8db724 100644 --- a/internal/xds/translator/testdata/in/xds-ir/http-route-request-headers.yaml +++ b/internal/xds/translator/testdata/in/xds-ir/http-route-request-headers.yaml @@ -18,20 +18,30 @@ http: - host: "1.2.3.4" port: 50000 addRequestHeaders: + - name: "some-header-multi-value" + value: + - "some-value" + - "some-additional-value" + append: true - name: "some-header" - value: "some-value" + value: + - "some-value" append: true - name: "some-header-2" - value: "some-value" + value: + - "some-value" append: true - name: "some-header3" - value: "some-value" + value: + - "some-value" append: false - name: "some-header4" - value: "some-value" + value: + - "some-value" append: false - name: "empty-header" - value: "" + value: + - "" append: false removeRequestHeaders: - "some-header5" diff --git a/internal/xds/translator/testdata/in/xds-ir/http-route-response-add-headers.yaml b/internal/xds/translator/testdata/in/xds-ir/http-route-response-add-headers.yaml index e3114e2d252..3cfaf5e4945 100644 --- a/internal/xds/translator/testdata/in/xds-ir/http-route-response-add-headers.yaml +++ b/internal/xds/translator/testdata/in/xds-ir/http-route-response-add-headers.yaml @@ -19,17 +19,22 @@ http: port: 50000 addResponseHeaders: - name: "some-header" - value: "some-value" + value: + - "some-value" append: true - name: "some-header-2" - value: "some-value" + value: + - "some-value" append: true - name: "some-header3" - value: "some-value" + value: + - "some-value" append: false - name: "some-header4" - value: "some-value" + value: + - "some-value" append: false - name: "empty-header" - value: "" + value: + - "" append: false diff --git a/internal/xds/translator/testdata/in/xds-ir/http-route-response-add-remove-headers.yaml b/internal/xds/translator/testdata/in/xds-ir/http-route-response-add-remove-headers.yaml index 0e59f8f124d..c97d927dff6 100644 --- a/internal/xds/translator/testdata/in/xds-ir/http-route-response-add-remove-headers.yaml +++ b/internal/xds/translator/testdata/in/xds-ir/http-route-response-add-remove-headers.yaml @@ -19,19 +19,24 @@ http: port: 50000 addResponseHeaders: - name: "some-header" - value: "some-value" + value: + - "some-value" append: true - name: "some-header-2" - value: "some-value" + value: + - "some-value" append: true - name: "some-header3" - value: "some-value" + value: + - "some-value" append: false - name: "some-header4" - value: "some-value" + value: + - "some-value" append: false - name: "empty-header" - value: "" + value: + - "" append: false removeResponseHeaders: - "some-header5" diff --git a/internal/xds/translator/testdata/in/xds-ir/http-route-weighted-backend-with-filters.yaml b/internal/xds/translator/testdata/in/xds-ir/http-route-weighted-backend-with-filters.yaml index f8943d07f01..8745e9893bc 100644 --- a/internal/xds/translator/testdata/in/xds-ir/http-route-weighted-backend-with-filters.yaml +++ b/internal/xds/translator/testdata/in/xds-ir/http-route-weighted-backend-with-filters.yaml @@ -19,7 +19,8 @@ http: addRequestHeaders: - append: false name: add-header-3 - value: some-value + value: + - some-value protocol: HTTP weight: 1 hostname: '*' @@ -37,10 +38,12 @@ http: addRequestHeaders: - append: true name: add-header-1 - value: some-value + value: + - some-value - append: true name: add-header-2 - value: some-value + value: + - some-value protocol: HTTP weight: 8 - addressType: IP diff --git a/internal/xds/translator/testdata/out/xds-ir/http-route-request-headers.routes.yaml b/internal/xds/translator/testdata/out/xds-ir/http-route-request-headers.routes.yaml index f91a70cb2ee..1f2c6be4057 100644 --- a/internal/xds/translator/testdata/out/xds-ir/http-route-request-headers.routes.yaml +++ b/internal/xds/translator/testdata/out/xds-ir/http-route-request-headers.routes.yaml @@ -9,6 +9,12 @@ prefix: / name: request-header-route requestHeadersToAdd: + - header: + key: some-header-multi-value + value: some-value + - header: + key: some-header-multi-value + value: some-additional-value - header: key: some-header value: some-value