Skip to content

Commit 2625c49

Browse files
committed
Add webhook limitation on header actions
Add an HTTPRoute webhook validation rule for RequestHeaderModifier and ResponseHeaderModifier filters. The rule rejects filters that contain multiple actions for the same header name.
1 parent 58667e3 commit 2625c49

File tree

2 files changed

+94
-0
lines changed

2 files changed

+94
-0
lines changed

apis/v1beta1/validation/httproute.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,12 @@ func validateHTTPRouteFilters(filters []gatewayv1b1.HTTPRouteFilter, matches []g
111111
if filter.URLRewrite != nil && filter.URLRewrite.Path != nil {
112112
errs = append(errs, validateHTTPPathModifier(*filter.URLRewrite.Path, matches, path.Index(i).Child("urlRewrite", "path"))...)
113113
}
114+
if filter.RequestHeaderModifier != nil {
115+
errs = append(errs, validateHTTPHeaderModifier(*filter.RequestHeaderModifier, path.Index(i).Child("requestHeaderModifier"))...)
116+
}
117+
if filter.ResponseHeaderModifier != nil {
118+
errs = append(errs, validateHTTPHeaderModifier(*filter.ResponseHeaderModifier, path.Index(i).Child("responseHeaderModifier"))...)
119+
}
114120
errs = append(errs, validateHTTPRouteFilterTypeMatchesValue(filter, path.Index(i))...)
115121
}
116122
// custom filters don't have any validation
@@ -276,6 +282,42 @@ func validateHTTPPathModifier(modifier gatewayv1b1.HTTPPathModifier, matches []g
276282
return errs
277283
}
278284

285+
func validateHTTPHeaderModifier(filter gatewayv1b1.HTTPHeaderFilter, path *field.Path) field.ErrorList {
286+
var errs field.ErrorList
287+
singleAction := make(map[string]bool)
288+
for i, action := range filter.Add {
289+
if needsErr, ok := singleAction[string(action.Name)]; ok {
290+
if needsErr {
291+
errs = append(errs, field.Invalid(path.Child("add"), filter.Add[i], "cannot specify multiple actions for header"))
292+
}
293+
singleAction[string(action.Name)] = false
294+
} else {
295+
singleAction[string(action.Name)] = true
296+
}
297+
}
298+
for i, action := range filter.Set {
299+
if needsErr, ok := singleAction[string(action.Name)]; ok {
300+
if needsErr {
301+
errs = append(errs, field.Invalid(path.Child("set"), filter.Set[i], "cannot specify multiple actions for header"))
302+
}
303+
singleAction[string(action.Name)] = false
304+
} else {
305+
singleAction[string(action.Name)] = true
306+
}
307+
}
308+
for i, action := range filter.Remove {
309+
if needsErr, ok := singleAction[action]; ok {
310+
if needsErr {
311+
errs = append(errs, field.Invalid(path.Child("remove"), filter.Remove[i], "cannot specify multiple actions for header"))
312+
}
313+
singleAction[action] = false
314+
} else {
315+
singleAction[action] = true
316+
}
317+
}
318+
return errs
319+
}
320+
279321
func hasExactlyOnePrefixMatch(matches []gatewayv1b1.HTTPRouteMatch) bool {
280322
if len(matches) != 1 || matches[0].Path == nil {
281323
return false

apis/v1beta1/validation/httproute_test.go

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,58 @@ func TestValidateHTTPRoute(t *testing.T) {
445445
},
446446
}},
447447
}},
448+
}, {
449+
name: "multiple actions for the same request header (invalid)",
450+
errCount: 2,
451+
rules: []gatewayv1b1.HTTPRouteRule{{
452+
Filters: []gatewayv1b1.HTTPRouteFilter{{
453+
Type: gatewayv1b1.HTTPRouteFilterRequestHeaderModifier,
454+
RequestHeaderModifier: &gatewayv1b1.HTTPHeaderFilter{
455+
Add: []gatewayv1b1.HTTPHeader{
456+
{
457+
Name: gatewayv1b1.HTTPHeaderName("x-fruit"),
458+
Value: "apple",
459+
},
460+
{
461+
Name: gatewayv1b1.HTTPHeaderName("x-vegetable"),
462+
Value: "carrot",
463+
},
464+
{
465+
Name: gatewayv1b1.HTTPHeaderName("x-grain"),
466+
Value: "rye",
467+
},
468+
},
469+
Set: []gatewayv1b1.HTTPHeader{
470+
{
471+
Name: gatewayv1b1.HTTPHeaderName("x-fruit"),
472+
Value: "watermelon",
473+
},
474+
{
475+
Name: gatewayv1b1.HTTPHeaderName("x-grain"),
476+
Value: "wheat",
477+
},
478+
},
479+
},
480+
}},
481+
}},
482+
}, {
483+
name: "multiple actions for the same response header (invalid)",
484+
errCount: 1,
485+
rules: []gatewayv1b1.HTTPRouteRule{{
486+
Filters: []gatewayv1b1.HTTPRouteFilter{{
487+
Type: gatewayv1b1.HTTPRouteFilterResponseHeaderModifier,
488+
ResponseHeaderModifier: &gatewayv1b1.HTTPHeaderFilter{
489+
Add: []gatewayv1b1.HTTPHeader{{
490+
Name: gatewayv1b1.HTTPHeaderName("x-example"),
491+
Value: "blueberry",
492+
}},
493+
Set: []gatewayv1b1.HTTPHeader{{
494+
Name: gatewayv1b1.HTTPHeaderName("x-example"),
495+
Value: "turnip",
496+
}},
497+
},
498+
}},
499+
}},
448500
}}
449501

450502
for _, tc := range tests {

0 commit comments

Comments
 (0)