1
0
Fork 0

Fix HTTPRoute Redirect Filter with port and scheme

Co-authored-by: Kevin Pollet <pollet.kevin@gmail.com>
This commit is contained in:
Romain 2024-06-06 10:56:03 +02:00 committed by GitHub
parent 7eac92f49c
commit 28d40e7f3c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 431 additions and 93 deletions

View file

@ -39,13 +39,7 @@ spec:
hostnames:
- "example.org"
rules:
- backendRefs:
- name: whoami
port: 80
weight: 1
kind: Service
group: ""
filters:
- filters:
- type: RequestRedirect
requestRedirect:
scheme: https

View file

@ -39,13 +39,7 @@ spec:
hostnames:
- "example.org"
rules:
- backendRefs:
- name: whoami
port: 80
weight: 1
kind: Service
group: ""
filters:
- filters:
- type: RequestRedirect
requestRedirect:
hostname: example.com

View file

@ -135,7 +135,7 @@ func (p *Provider) loadHTTPRoute(ctx context.Context, client Client, listener ga
var wrr dynamic.WeightedRoundRobin
wrrName := provider.Normalize(routerKey + "-wrr")
middlewares, err := p.loadMiddlewares(listener.Protocol, route.Namespace, routerKey, routeRule.Filters)
middlewares, err := p.loadMiddlewares(route.Namespace, routerKey, routeRule.Filters)
if err != nil {
log.Ctx(ctx).Error().
Err(err).
@ -294,14 +294,14 @@ func (p *Provider) loadHTTPBackendRef(namespace string, backendRef gatev1.HTTPBa
return backendFunc(string(backendRef.Name), namespace)
}
func (p *Provider) loadMiddlewares(listenerProtocol gatev1.ProtocolType, namespace, prefix string, filters []gatev1.HTTPRouteFilter) (map[string]*dynamic.Middleware, error) {
func (p *Provider) loadMiddlewares(namespace, prefix string, filters []gatev1.HTTPRouteFilter) (map[string]*dynamic.Middleware, error) {
middlewares := make(map[string]*dynamic.Middleware)
for i, filter := range filters {
switch filter.Type {
case gatev1.HTTPRouteFilterRequestRedirect:
middlewareName := provider.Normalize(fmt.Sprintf("%s-%s-%d", prefix, strings.ToLower(string(filter.Type)), i))
middlewares[middlewareName] = createRedirectRegexMiddleware(listenerProtocol, filter.RequestRedirect)
middlewares[middlewareName] = createRedirectMiddleware(filter.RequestRedirect)
case gatev1.HTTPRouteFilterRequestHeaderModifier:
middlewareName := provider.Normalize(fmt.Sprintf("%s-%s-%d", prefix, strings.ToLower(string(filter.Type)), i))
@ -573,25 +573,27 @@ func createRequestHeaderModifier(filter *gatev1.HTTPHeaderFilter) *dynamic.Middl
}
}
func createRedirectRegexMiddleware(listenerProtocol gatev1.ProtocolType, filter *gatev1.HTTPRequestRedirectFilter) *dynamic.Middleware {
// The spec allows for an empty string in which case we should use the
// scheme of the request which in this case is the listener scheme.
filterScheme := ptr.Deref(filter.Scheme, strings.ToLower(string(listenerProtocol)))
statusCode := ptr.Deref(filter.StatusCode, http.StatusFound)
func createRedirectMiddleware(filter *gatev1.HTTPRequestRedirectFilter) *dynamic.Middleware {
filterScheme := ptr.Deref(filter.Scheme, "${scheme}")
port := "${port}"
if filterScheme == "http" || filterScheme == "https" {
port = ""
}
if filter.Port != nil {
port = fmt.Sprintf(":%d", *filter.Port)
}
statusCode := ptr.Deref(filter.StatusCode, http.StatusFound)
hostname := "${hostname}"
if filter.Hostname != nil && *filter.Hostname != "" {
hostname = string(*filter.Hostname)
}
return &dynamic.Middleware{
RedirectRegex: &dynamic.RedirectRegex{
Regex: `^[a-z]+:\/\/(?P<userInfo>.+@)?(?P<hostname>\[[\w:\.]+\]|[\w\._-]+)(?P<port>:\d+)?\/(?P<path>.*)`,
RequestRedirect: &dynamic.RequestRedirect{
Regex: `^(?P<scheme>[a-z]+):\/\/(?P<userinfo>.+@)?(?P<hostname>\[[\w:\.]+\]|[\w\._-]+)(?P<port>:\d+)?\/(?P<path>.*)`,
Replacement: fmt.Sprintf("%s://${userinfo}%s%s/${path}", filterScheme, hostname, port),
Permanent: statusCode == http.StatusMovedPermanently,
},

View file

@ -1669,39 +1669,16 @@ func TestLoadHTTPRoutes(t *testing.T) {
},
Middlewares: map[string]*dynamic.Middleware{
"default-http-app-1-my-gateway-web-fa136e10345bd0e7248d-requestredirect-0": {
RedirectRegex: &dynamic.RedirectRegex{
Regex: "^[a-z]+:\\/\\/(?P<userInfo>.+@)?(?P<hostname>\\[[\\w:\\.]+\\]|[\\w\\._-]+)(?P<port>:\\d+)?\\/(?P<path>.*)",
Replacement: "https://${userinfo}${hostname}${port}/${path}",
RequestRedirect: &dynamic.RequestRedirect{
Regex: "^(?P<scheme>[a-z]+):\\/\\/(?P<userinfo>.+@)?(?P<hostname>\\[[\\w:\\.]+\\]|[\\w\\._-]+)(?P<port>:\\d+)?\\/(?P<path>.*)",
Replacement: "https://${userinfo}${hostname}/${path}",
Permanent: true,
},
},
},
Services: map[string]*dynamic.Service{
"default-http-app-1-my-gateway-web-fa136e10345bd0e7248d-wrr": {
Weighted: &dynamic.WeightedRoundRobin{
Services: []dynamic.WRRService{
{
Name: "default-whoami-80",
Weight: ptr.To(1),
},
},
},
},
"default-whoami-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: "http://10.10.0.1:80",
},
{
URL: "http://10.10.0.2:80",
},
},
PassHostHeader: ptr.To(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
},
Weighted: &dynamic.WeightedRoundRobin{},
},
},
ServersTransports: map[string]*dynamic.ServersTransport{},
@ -1739,38 +1716,15 @@ func TestLoadHTTPRoutes(t *testing.T) {
},
Middlewares: map[string]*dynamic.Middleware{
"default-http-app-1-my-gateway-web-fa136e10345bd0e7248d-requestredirect-0": {
RedirectRegex: &dynamic.RedirectRegex{
Regex: "^[a-z]+:\\/\\/(?P<userInfo>.+@)?(?P<hostname>\\[[\\w:\\.]+\\]|[\\w\\._-]+)(?P<port>:\\d+)?\\/(?P<path>.*)",
Replacement: "http://${userinfo}example.com:443/${path}",
RequestRedirect: &dynamic.RequestRedirect{
Regex: "^(?P<scheme>[a-z]+):\\/\\/(?P<userinfo>.+@)?(?P<hostname>\\[[\\w:\\.]+\\]|[\\w\\._-]+)(?P<port>:\\d+)?\\/(?P<path>.*)",
Replacement: "${scheme}://${userinfo}example.com:443/${path}",
},
},
},
Services: map[string]*dynamic.Service{
"default-http-app-1-my-gateway-web-fa136e10345bd0e7248d-wrr": {
Weighted: &dynamic.WeightedRoundRobin{
Services: []dynamic.WRRService{
{
Name: "default-whoami-80",
Weight: ptr.To(1),
},
},
},
},
"default-whoami-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: "http://10.10.0.1:80",
},
{
URL: "http://10.10.0.2:80",
},
},
PassHostHeader: ptr.To(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
},
Weighted: &dynamic.WeightedRoundRobin{},
},
},
ServersTransports: map[string]*dynamic.ServersTransport{},