Skip to content

Commit 01c0b52

Browse files
committed
host header is not allowed to be modified
Signed-off-by: Huabing (Robin) Zhao <[email protected]>
1 parent fcdab90 commit 01c0b52

5 files changed

+379
-116
lines changed

internal/gatewayapi/filters.go

+77-96
Original file line numberDiff line numberDiff line change
@@ -453,28 +453,19 @@ func (t *Translator) processRequestHeaderModifierFilter(
453453
for _, addHeader := range headersToAdd {
454454
emptyFilterConfig = false
455455
if addHeader.Name == "" {
456-
routeStatus := GetRouteStatus(filterContext.Route)
457-
status.SetRouteStatusCondition(routeStatus,
458-
filterContext.ParentRef.routeParentStatusIdx,
459-
filterContext.Route.GetGeneration(),
460-
gwapiv1.RouteConditionAccepted,
461-
metav1.ConditionFalse,
462-
gwapiv1.RouteReasonUnsupportedValue,
456+
updateRouteStatusForRHMFilter(
457+
filterContext,
463458
"RequestHeaderModifier Filter cannot add a header with an empty name",
464459
)
465460
// try to process the rest of the headers and produce a valid config.
466461
continue
467462
}
468-
// Per Gateway API specification on HTTPHeaderName, : and / are invalid characters in header names
469-
if strings.Contains(string(addHeader.Name), "/") || strings.Contains(string(addHeader.Name), ":") {
470-
routeStatus := GetRouteStatus(filterContext.Route)
471-
status.SetRouteStatusCondition(routeStatus,
472-
filterContext.ParentRef.routeParentStatusIdx,
473-
filterContext.Route.GetGeneration(),
474-
gwapiv1.RouteConditionAccepted,
475-
metav1.ConditionFalse,
476-
gwapiv1.RouteReasonUnsupportedValue,
477-
fmt.Sprintf("RequestHeaderModifier Filter cannot set headers with a '/' or ':' character in them. Header: %q", string(addHeader.Name)),
463+
if !isModifiableHeader(string(addHeader.Name)) {
464+
updateRouteStatusForRHMFilter(
465+
filterContext,
466+
fmt.Sprintf(
467+
"RequestHeaderModifier Filter cannot set headers with a '/' or ':' character in them, or the host header. Header: %q",
468+
string(addHeader.Name)),
478469
)
479470
continue
480471
}
@@ -510,27 +501,19 @@ func (t *Translator) processRequestHeaderModifierFilter(
510501
for _, setHeader := range headersToSet {
511502

512503
if setHeader.Name == "" {
513-
routeStatus := GetRouteStatus(filterContext.Route)
514-
status.SetRouteStatusCondition(routeStatus,
515-
filterContext.ParentRef.routeParentStatusIdx,
516-
filterContext.Route.GetGeneration(),
517-
gwapiv1.RouteConditionAccepted,
518-
metav1.ConditionFalse,
519-
gwapiv1.RouteReasonUnsupportedValue,
504+
updateRouteStatusForRHMFilter(
505+
filterContext,
520506
"RequestHeaderModifier Filter cannot set a header with an empty name",
521507
)
522508
continue
523509
}
524-
// Per Gateway API specification on HTTPHeaderName, : and / are invalid characters in header names
525-
if strings.Contains(string(setHeader.Name), "/") || strings.Contains(string(setHeader.Name), ":") {
526-
routeStatus := GetRouteStatus(filterContext.Route)
527-
status.SetRouteStatusCondition(routeStatus,
528-
filterContext.ParentRef.routeParentStatusIdx,
529-
filterContext.Route.GetGeneration(),
530-
gwapiv1.RouteConditionAccepted,
531-
metav1.ConditionFalse,
532-
gwapiv1.RouteReasonUnsupportedValue,
533-
fmt.Sprintf("RequestHeaderModifier Filter cannot set headers with a '/' or ':' character in them. Header: '%s'", string(setHeader.Name)),
510+
511+
if !isModifiableHeader(string(setHeader.Name)) {
512+
updateRouteStatusForRHMFilter(
513+
filterContext,
514+
fmt.Sprintf(
515+
"RequestHeaderModifier Filter cannot set headers with a '/' or ':' character in them, or the host header. Header: %q",
516+
string(setHeader.Name)),
534517
)
535518
continue
536519
}
@@ -566,18 +549,23 @@ func (t *Translator) processRequestHeaderModifierFilter(
566549
}
567550
for _, removedHeader := range headersToRemove {
568551
if removedHeader == "" {
569-
routeStatus := GetRouteStatus(filterContext.Route)
570-
status.SetRouteStatusCondition(routeStatus,
571-
filterContext.ParentRef.routeParentStatusIdx,
572-
filterContext.Route.GetGeneration(),
573-
gwapiv1.RouteConditionAccepted,
574-
metav1.ConditionFalse,
575-
gwapiv1.RouteReasonUnsupportedValue,
552+
updateRouteStatusForRHMFilter(
553+
filterContext,
576554
"RequestHeaderModifier Filter cannot remove a header with an empty name",
577555
)
578556
continue
579557
}
580558

559+
if !isModifiableHeader(removedHeader) {
560+
updateRouteStatusForRHMFilter(
561+
filterContext,
562+
fmt.Sprintf(
563+
"RequestHeaderModifier Filter cannot remove headers with a '/' or ':' character in them, or the host header. Header: %q",
564+
removedHeader),
565+
)
566+
continue
567+
}
568+
581569
canRemHeader := true
582570
for _, h := range filterContext.RemoveRequestHeaders {
583571
if strings.EqualFold(h, removedHeader) {
@@ -595,18 +583,31 @@ func (t *Translator) processRequestHeaderModifierFilter(
595583

596584
// Update the status if the filter failed to configure any valid headers to add/remove
597585
if len(filterContext.AddRequestHeaders) == 0 && len(filterContext.RemoveRequestHeaders) == 0 && !emptyFilterConfig {
598-
routeStatus := GetRouteStatus(filterContext.Route)
599-
status.SetRouteStatusCondition(routeStatus,
600-
filterContext.ParentRef.routeParentStatusIdx,
601-
filterContext.Route.GetGeneration(),
602-
gwapiv1.RouteConditionAccepted,
603-
metav1.ConditionFalse,
604-
gwapiv1.RouteReasonUnsupportedValue,
586+
updateRouteStatusForRHMFilter(
587+
filterContext,
605588
"RequestHeaderModifier Filter did not provide valid configuration to add/set/remove any headers",
606589
)
607590
}
608591
}
609592

593+
func updateRouteStatusForRHMFilter(filterContext *HTTPFiltersContext, message string) {
594+
routeStatus := GetRouteStatus(filterContext.Route)
595+
status.SetRouteStatusCondition(routeStatus,
596+
filterContext.ParentRef.routeParentStatusIdx,
597+
filterContext.Route.GetGeneration(),
598+
gwapiv1.RouteConditionAccepted,
599+
metav1.ConditionFalse,
600+
gwapiv1.RouteReasonUnsupportedValue,
601+
message,
602+
)
603+
}
604+
605+
func isModifiableHeader(headerName string) bool {
606+
// Per Gateway API specification on HTTPHeaderName, : and / are invalid characters in header names
607+
// And Envoy does not allow modification the pseudo headers and the host header
608+
return !strings.Contains(headerName, "/") && !strings.Contains(headerName, ":") && !strings.EqualFold(headerName, "host")
609+
}
610+
610611
func (t *Translator) processResponseHeaderModifierFilter(
611612
headerModifier *gwapiv1.HTTPHeaderFilter,
612613
filterContext *HTTPFiltersContext,
@@ -625,28 +626,18 @@ func (t *Translator) processResponseHeaderModifierFilter(
625626
for _, addHeader := range headersToAdd {
626627
emptyFilterConfig = false
627628
if addHeader.Name == "" {
628-
routeStatus := GetRouteStatus(filterContext.Route)
629-
status.SetRouteStatusCondition(routeStatus,
630-
filterContext.ParentRef.routeParentStatusIdx,
631-
filterContext.Route.GetGeneration(),
632-
gwapiv1.RouteConditionAccepted,
633-
metav1.ConditionFalse,
634-
gwapiv1.RouteReasonUnsupportedValue,
629+
updateRouteStatusForRHMFilter(
630+
filterContext,
635631
"ResponseHeaderModifier Filter cannot add a header with an empty name",
636632
)
637633
// try to process the rest of the headers and produce a valid config.
638634
continue
639635
}
640-
// Per Gateway API specification on HTTPHeaderName, : and / are invalid characters in header names
641-
if strings.Contains(string(addHeader.Name), "/") || strings.Contains(string(addHeader.Name), ":") {
642-
routeStatus := GetRouteStatus(filterContext.Route)
643-
status.SetRouteStatusCondition(routeStatus,
644-
filterContext.ParentRef.routeParentStatusIdx,
645-
filterContext.Route.GetGeneration(),
646-
gwapiv1.RouteConditionAccepted,
647-
metav1.ConditionFalse,
648-
gwapiv1.RouteReasonUnsupportedValue,
649-
fmt.Sprintf("ResponseHeaderModifier Filter cannot set headers with a '/' or ':' character in them. Header: %q", string(addHeader.Name)),
636+
if !isModifiableHeader(string(addHeader.Name)) {
637+
updateRouteStatusForRHMFilter(
638+
filterContext,
639+
fmt.Sprintf("ResponseHeaderModifier Filter cannot set headers with a '/' or ':' character in them, or the host header. Header: %q",
640+
string(addHeader.Name)),
650641
)
651642
continue
652643
}
@@ -682,27 +673,18 @@ func (t *Translator) processResponseHeaderModifierFilter(
682673
for _, setHeader := range headersToSet {
683674

684675
if setHeader.Name == "" {
685-
routeStatus := GetRouteStatus(filterContext.Route)
686-
status.SetRouteStatusCondition(routeStatus,
687-
filterContext.ParentRef.routeParentStatusIdx,
688-
filterContext.Route.GetGeneration(),
689-
gwapiv1.RouteConditionAccepted,
690-
metav1.ConditionFalse,
691-
gwapiv1.RouteReasonUnsupportedValue,
676+
updateRouteStatusForRHMFilter(
677+
filterContext,
692678
"ResponseHeaderModifier Filter cannot set a header with an empty name",
693679
)
694680
continue
695681
}
696-
// Per Gateway API specification on HTTPHeaderName, : and / are invalid characters in header names
697-
if strings.Contains(string(setHeader.Name), "/") || strings.Contains(string(setHeader.Name), ":") {
698-
routeStatus := GetRouteStatus(filterContext.Route)
699-
status.SetRouteStatusCondition(routeStatus,
700-
filterContext.ParentRef.routeParentStatusIdx,
701-
filterContext.Route.GetGeneration(),
702-
gwapiv1.RouteConditionAccepted,
703-
metav1.ConditionFalse,
704-
gwapiv1.RouteReasonUnsupportedValue,
705-
fmt.Sprintf("ResponseHeaderModifier Filter cannot set headers with a '/' or ':' character in them. Header: '%s'", string(setHeader.Name)),
682+
683+
if !isModifiableHeader(string(setHeader.Name)) {
684+
updateRouteStatusForRHMFilter(
685+
filterContext,
686+
fmt.Sprintf("ResponseHeaderModifier Filter cannot set headers with a '/' or ':' character in them, or the host header. Header: %q",
687+
string(setHeader.Name)),
706688
)
707689
continue
708690
}
@@ -738,17 +720,21 @@ func (t *Translator) processResponseHeaderModifierFilter(
738720
}
739721
for _, removedHeader := range headersToRemove {
740722
if removedHeader == "" {
741-
routeStatus := GetRouteStatus(filterContext.Route)
742-
status.SetRouteStatusCondition(routeStatus,
743-
filterContext.ParentRef.routeParentStatusIdx,
744-
filterContext.Route.GetGeneration(),
745-
gwapiv1.RouteConditionAccepted,
746-
metav1.ConditionFalse,
747-
gwapiv1.RouteReasonUnsupportedValue,
723+
updateRouteStatusForRHMFilter(
724+
filterContext,
748725
"ResponseHeaderModifier Filter cannot remove a header with an empty name",
749726
)
750727
continue
751728
}
729+
if !isModifiableHeader(removedHeader) {
730+
updateRouteStatusForRHMFilter(
731+
filterContext,
732+
fmt.Sprintf(
733+
"ResponseHeaderModifier Filter cannot remove headers with a '/' or ':' character in them, or the host header. Header: %q",
734+
removedHeader),
735+
)
736+
continue
737+
}
752738

753739
canRemHeader := true
754740
for _, h := range filterContext.RemoveResponseHeaders {
@@ -768,13 +754,8 @@ func (t *Translator) processResponseHeaderModifierFilter(
768754

769755
// Update the status if the filter failed to configure any valid headers to add/remove
770756
if len(filterContext.AddResponseHeaders) == 0 && len(filterContext.RemoveResponseHeaders) == 0 && !emptyFilterConfig {
771-
routeStatus := GetRouteStatus(filterContext.Route)
772-
status.SetRouteStatusCondition(routeStatus,
773-
filterContext.ParentRef.routeParentStatusIdx,
774-
filterContext.Route.GetGeneration(),
775-
gwapiv1.RouteConditionAccepted,
776-
metav1.ConditionFalse,
777-
gwapiv1.RouteReasonUnsupportedValue,
757+
updateRouteStatusForRHMFilter(
758+
filterContext,
778759
"ResponseHeaderModifier Filter did not provide valid configuration to add/set/remove any headers",
779760
)
780761
}

internal/gatewayapi/testdata/httproute-with-header-filter-invalid-headers.in.yaml

+54-4
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ httpRoutes:
3030
rules:
3131
- matches:
3232
- path:
33-
value: "/"
33+
value: "/bar"
3434
backendRefs:
3535
- name: service-1
3636
port: 8080
@@ -42,7 +42,57 @@ httpRoutes:
4242
value: "some-value"
4343
- name: "good-header"
4444
value: "some-value"
45-
add:
46-
- name: "example/2"
45+
- apiVersion: gateway.networking.k8s.io/v1
46+
kind: HTTPRoute
47+
metadata:
48+
namespace: default
49+
name: httproute-2
50+
spec:
51+
hostnames:
52+
- gateway.envoyproxy.io
53+
parentRefs:
54+
- namespace: envoy-gateway
55+
name: gateway-1
56+
sectionName: http
57+
rules:
58+
- matches:
59+
- path:
60+
value: "/baz"
61+
backendRefs:
62+
- name: service-1
63+
port: 8080
64+
filters:
65+
- type: RequestHeaderModifier
66+
requestHeaderModifier:
67+
remove:
68+
- "example/2"
69+
set:
70+
- name: "good-header"
71+
value: "some-value"
72+
- apiVersion: gateway.networking.k8s.io/v1
73+
kind: HTTPRoute
74+
metadata:
75+
namespace: default
76+
name: httproute-3
77+
spec:
78+
hostnames:
79+
- gateway.envoyproxy.io
80+
parentRefs:
81+
- namespace: envoy-gateway
82+
name: gateway-1
83+
sectionName: http
84+
rules:
85+
- matches:
86+
- path:
87+
value: "/qux"
88+
backendRefs:
89+
- name: service-1
90+
port: 8080
91+
filters:
92+
- type: RequestHeaderModifier
93+
requestHeaderModifier:
94+
set:
95+
- name: "host"
96+
value: "example.com"
97+
- name: "good-header"
4798
value: "some-value"
48-

0 commit comments

Comments
 (0)