Skip to content

Commit 0f2974d

Browse files
committed
support HTTPCORSFilter
Signed-off-by: Huabing (Robin) Zhao <[email protected]>
1 parent 68a7d6f commit 0f2974d

18 files changed

+844
-229
lines changed

internal/gatewayapi/filters.go

+53
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"fmt"
1010
"regexp"
1111
"strings"
12+
"time"
1213

1314
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1415
"k8s.io/utils/ptr"
@@ -59,6 +60,8 @@ type HTTPFilterIR struct {
5960

6061
Mirrors []*ir.MirrorPolicy
6162

63+
CORS *ir.CORS
64+
6265
ExtensionRefs []*ir.UnstructuredRef
6366
}
6467

@@ -98,6 +101,8 @@ func (t *Translator) ProcessHTTPFilters(parentRef *RouteParentContext,
98101
t.processResponseHeaderModifierFilter(filter.ResponseHeaderModifier, httpFiltersContext)
99102
case gwapiv1.HTTPRouteFilterRequestMirror:
100103
err = t.processRequestMirrorFilter(i, filter.RequestMirror, httpFiltersContext, resources)
104+
case gwapiv1.HTTPRouteFilterCORS:
105+
t.processCORSFilter(filter.CORS, httpFiltersContext)
101106
case gwapiv1.HTTPRouteFilterExtensionRef:
102107
t.processExtensionRefHTTPFilter(filter.ExtensionRef, httpFiltersContext, resources)
103108
default:
@@ -891,6 +896,54 @@ func (t *Translator) processRequestMirrorFilter(
891896
return nil
892897
}
893898

899+
func (t *Translator) processCORSFilter(
900+
corsFilter *gwapiv1.HTTPCORSFilter,
901+
filterContext *HTTPFiltersContext,
902+
) {
903+
// Make sure the config actually exists
904+
if corsFilter == nil {
905+
return
906+
}
907+
908+
var allowOrigins []*ir.StringMatch
909+
for _, origin := range corsFilter.AllowOrigins {
910+
if containsWildcard(string(origin)) {
911+
regexStr := wildcard2regex(string(origin))
912+
allowOrigins = append(allowOrigins, &ir.StringMatch{
913+
SafeRegex: &regexStr,
914+
})
915+
} else {
916+
allowOrigins = append(allowOrigins, &ir.StringMatch{
917+
Exact: (*string)(&origin),
918+
})
919+
}
920+
}
921+
922+
var allowMethods []string
923+
for _, method := range corsFilter.AllowMethods {
924+
allowMethods = append(allowMethods, string(method))
925+
}
926+
927+
var allowHeaders []string
928+
for _, header := range corsFilter.AllowHeaders {
929+
allowHeaders = append(allowHeaders, string(header))
930+
}
931+
932+
var exposeHeaders []string
933+
for _, header := range corsFilter.ExposeHeaders {
934+
exposeHeaders = append(exposeHeaders, string(header))
935+
}
936+
937+
filterContext.CORS = &ir.CORS{
938+
AllowOrigins: allowOrigins,
939+
AllowMethods: allowMethods,
940+
AllowHeaders: allowHeaders,
941+
ExposeHeaders: exposeHeaders,
942+
MaxAge: ptr.To(metav1.Duration{Duration: time.Duration(corsFilter.MaxAge) * time.Second}),
943+
AllowCredentials: bool(corsFilter.AllowCredentials),
944+
}
945+
}
946+
894947
func (t *Translator) processUnresolvedHTTPFilter(errMsg string, filterContext *HTTPFiltersContext) {
895948
routeStatus := GetRouteStatus(filterContext.Route)
896949
status.SetRouteStatusCondition(routeStatus,

internal/gatewayapi/helpers.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,8 @@ func ValidateHTTPRouteFilter(filter *gwapiv1.HTTPRouteFilter, extGKs ...schema.G
175175
filter.Type == gwapiv1.HTTPRouteFilterURLRewrite ||
176176
filter.Type == gwapiv1.HTTPRouteFilterRequestRedirect ||
177177
filter.Type == gwapiv1.HTTPRouteFilterRequestHeaderModifier ||
178-
filter.Type == gwapiv1.HTTPRouteFilterResponseHeaderModifier:
178+
filter.Type == gwapiv1.HTTPRouteFilterResponseHeaderModifier ||
179+
filter.Type == gwapiv1.HTTPRouteFilterCORS:
179180
return nil
180181
case filter.Type == gwapiv1.HTTPRouteFilterExtensionRef:
181182
switch {

internal/gatewayapi/route.go

+6-22
Original file line numberDiff line numberDiff line change
@@ -504,6 +504,9 @@ func applyHTTPFiltersContextToIRRoute(httpFiltersContext *HTTPFiltersContext, ir
504504
if httpFiltersContext.Mirrors != nil {
505505
irRoute.Mirrors = httpFiltersContext.Mirrors
506506
}
507+
if httpFiltersContext.CORS != nil {
508+
irRoute.CORS = httpFiltersContext.CORS
509+
}
507510

508511
if len(httpFiltersContext.ExtensionRefs) > 0 {
509512
irRoute.ExtensionRefs = httpFiltersContext.ExtensionRefs
@@ -779,28 +782,9 @@ func (t *Translator) processHTTPRouteParentRefListener(route RouteContext, route
779782
// Remove dots from the hostname before appending it to the IR Route name
780783
// since dots are special chars used in stats tag extraction in Envoy
781784
underscoredHost := strings.ReplaceAll(host, ".", "_")
782-
hostRoute := &ir.HTTPRoute{
783-
Name: fmt.Sprintf("%s/%s", routeRoute.Name, underscoredHost),
784-
Metadata: routeRoute.Metadata,
785-
Hostname: host,
786-
PathMatch: routeRoute.PathMatch,
787-
HeaderMatches: routeRoute.HeaderMatches,
788-
QueryParamMatches: routeRoute.QueryParamMatches,
789-
AddRequestHeaders: routeRoute.AddRequestHeaders,
790-
RemoveRequestHeaders: routeRoute.RemoveRequestHeaders,
791-
AddResponseHeaders: routeRoute.AddResponseHeaders,
792-
RemoveResponseHeaders: routeRoute.RemoveResponseHeaders,
793-
Destination: routeRoute.Destination,
794-
Redirect: routeRoute.Redirect,
795-
DirectResponse: routeRoute.DirectResponse,
796-
URLRewrite: routeRoute.URLRewrite,
797-
Mirrors: routeRoute.Mirrors,
798-
ExtensionRefs: routeRoute.ExtensionRefs,
799-
IsHTTP2: routeRoute.IsHTTP2,
800-
SessionPersistence: routeRoute.SessionPersistence,
801-
Timeout: routeRoute.Timeout,
802-
Retry: routeRoute.Retry,
803-
}
785+
hostRoute := routeRoute.DeepCopy()
786+
hostRoute.Name = fmt.Sprintf("%s/%s", routeRoute.Name, underscoredHost)
787+
hostRoute.Hostname = host
804788
perHostRoutes = append(perHostRoutes, hostRoute)
805789
}
806790
}

internal/gatewayapi/securitypolicy.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -600,7 +600,7 @@ func (t *Translator) buildCORS(cors *egv1a1.CORS) *ir.CORS {
600600
var allowOrigins []*ir.StringMatch
601601

602602
for _, origin := range cors.AllowOrigins {
603-
if isWildcard(string(origin)) {
603+
if containsWildcard(string(origin)) {
604604
regexStr := wildcard2regex(string(origin))
605605
allowOrigins = append(allowOrigins, &ir.StringMatch{
606606
SafeRegex: &regexStr,
@@ -622,7 +622,7 @@ func (t *Translator) buildCORS(cors *egv1a1.CORS) *ir.CORS {
622622
}
623623
}
624624

625-
func isWildcard(s string) bool {
625+
func containsWildcard(s string) bool {
626626
return strings.ContainsAny(s, "*")
627627
}
628628

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
gateways:
2+
- apiVersion: gateway.networking.k8s.io/v1
3+
kind: Gateway
4+
metadata:
5+
namespace: envoy-gateway
6+
name: gateway-1
7+
spec:
8+
gatewayClassName: envoy-gateway-class
9+
listeners:
10+
- name: http
11+
protocol: HTTP
12+
port: 80
13+
hostname: "*.envoyproxy.io"
14+
allowedRoutes:
15+
namespaces:
16+
from: All
17+
httpRoutes:
18+
- apiVersion: gateway.networking.k8s.io/v1
19+
kind: HTTPRoute
20+
metadata:
21+
namespace: default
22+
name: httproute-cors-exact
23+
spec:
24+
hostnames:
25+
- gateway.envoyproxy.io
26+
parentRefs:
27+
- namespace: envoy-gateway
28+
name: gateway-1
29+
sectionName: http
30+
rules:
31+
- matches:
32+
- path:
33+
value: "/foo"
34+
backendRefs:
35+
- name: service-1
36+
port: 8080
37+
filters:
38+
- type: CORS
39+
cors:
40+
allowOrigins:
41+
- "https://gateway.envoyproxy.io"
42+
allowMethods:
43+
- GET
44+
- POST
45+
- PUT
46+
- DELETE
47+
allowHeaders:
48+
- header1
49+
- header2
50+
exposeHeaders:
51+
- header3
52+
- header4
53+
allowCredentials: true
54+
maxAge: 1000
55+
56+
- apiVersion: gateway.networking.k8s.io/v1
57+
kind: HTTPRoute
58+
metadata:
59+
namespace: default
60+
name: httproute-cors-wildcard
61+
spec:
62+
hostnames:
63+
- gateway.envoyproxy.io
64+
parentRefs:
65+
- namespace: envoy-gateway
66+
name: gateway-1
67+
sectionName: http
68+
rules:
69+
- matches:
70+
- path:
71+
value: "/bar"
72+
backendRefs:
73+
- name: service-1
74+
port: 8080
75+
filters:
76+
- type: CORS
77+
cors:
78+
allowOrigins:
79+
- "https://*.envoyproxy.io"
80+
allowMethods:
81+
- "*"
82+
- POST
83+
- PUT
84+
- DELETE

0 commit comments

Comments
 (0)