Skip to content

Commit

Permalink
feat(httproute): handle URLRewrite filter's hostname rewrite
Browse files Browse the repository at this point in the history
  • Loading branch information
czeslavo committed Apr 29, 2024
1 parent 60e7b41 commit 45546f1
Show file tree
Hide file tree
Showing 3 changed files with 123 additions and 51 deletions.
77 changes: 53 additions & 24 deletions internal/dataplane/translator/subtranslator/httproute.go
Original file line number Diff line number Diff line change
Expand Up @@ -439,14 +439,12 @@ func generatePluginsFromHTTPRouteFilters(
pluginNamesFromExtensionRef = append(pluginNamesFromExtensionRef, plugin)

case gatewayapi.HTTPRouteFilterURLRewrite:
plugin, routeModifier, err := generateRequestTransformerForURLRewrite(filter.URLRewrite, path, expressionsRouterEnabled)
plugins, routeModifiers, err := generateRequestTransformerForURLRewrite(filter.URLRewrite, path, expressionsRouterEnabled)
if err != nil {
return httpRouteFiltersOriginatedPlugins{}, err
}
kongPlugins = append(kongPlugins, plugin)
if routeModifier != nil {
kongRouteModifiers = append(kongRouteModifiers, routeModifier)
}
kongPlugins = append(kongPlugins, plugins...)
kongRouteModifiers = append(kongRouteModifiers, routeModifiers...)

case gatewayapi.HTTPRouteFilterRequestMirror:
// not supported
Expand Down Expand Up @@ -632,36 +630,67 @@ func generateRequestTransformerForURLRewrite(
filter *gatewayapi.HTTPURLRewriteFilter,
path string,
expressionsRouterEnabled bool,
) (kong.Plugin, kongRouteModifier, error) {
) ([]kong.Plugin, []kongRouteModifier, error) {
if filter == nil {
return kong.Plugin{}, nil, fmt.Errorf("%s is not provided", gatewayapi.HTTPRouteFilterURLRewrite)
return nil, nil, fmt.Errorf("%s is not provided", gatewayapi.HTTPRouteFilterURLRewrite)
}

if filter.Path == nil && filter.Hostname == nil {
return kong.Plugin{}, nil, fmt.Errorf("%s missing Path and Hostname", gatewayapi.HTTPRouteFilterURLRewrite)
return nil, nil, fmt.Errorf("%s missing Path and Hostname", gatewayapi.HTTPRouteFilterURLRewrite)
}

var (
plugins []kong.Plugin
routeModifiers []kongRouteModifier
)
if filter.Path != nil {
switch filter.Path.Type {
case gatewayapi.FullPathHTTPPathModifier:
plugin, err := generateRequestTransformerForURLRewriteFullPath(filter)
if err != nil {
return kong.Plugin{}, nil, fmt.Errorf("failed to generate request-transformer plugin for %s: %w", gatewayapi.HTTPRouteFilterURLRewrite, err)
}
return plugin, nil, nil

case gatewayapi.PrefixMatchHTTPPathModifier:
plugin, routeModifier := generateRequestTransformerForURLRewritePrefixMatch(filter, path, expressionsRouterEnabled)
return plugin, routeModifier, nil
plugin, modifier, err := generateRequestTransformerForURLRewritePath(filter, path, expressionsRouterEnabled)
if err != nil {
return nil, nil, fmt.Errorf("failed to generate request-transformer plugin for Path: %w", err)
}
plugins = append(plugins, plugin)
if modifier != nil {
routeModifiers = append(routeModifiers, modifier)
}
}

// TODO: https://github.com/Kong/kubernetes-ingress-controller/issues/3685
if filter.Hostname != nil {
return kong.Plugin{}, nil, fmt.Errorf("unsupported hostname replace for %s", gatewayapi.HTTPRouteFilterURLRewrite)
plugins = append(plugins, generateRequestTransformerForURLRewriteHostname(filter))
}

return kong.Plugin{}, nil, fmt.Errorf("invalid %s config", gatewayapi.HTTPRouteFilterURLRewrite)
return plugins, routeModifiers, nil
}

func generateRequestTransformerForURLRewritePath(
filter *gatewayapi.HTTPURLRewriteFilter,
path string,
expressionsRouterEnabled bool,
) (kong.Plugin, kongRouteModifier, error) {
switch filter.Path.Type {
case gatewayapi.FullPathHTTPPathModifier:
plugin, err := generateRequestTransformerForURLRewriteFullPath(filter)
if err != nil {
return kong.Plugin{}, nil, fmt.Errorf("failed to generate request-transformer plugin for %s: %w", gatewayapi.HTTPRouteFilterURLRewrite, err)
}
return plugin, nil, nil

case gatewayapi.PrefixMatchHTTPPathModifier:
plugin, routeModifier := generateRequestTransformerForURLRewritePrefixMatch(filter, path, expressionsRouterEnabled)
return plugin, routeModifier, nil
default:
return kong.Plugin{}, nil, fmt.Errorf("unsupported path type %s for %s", filter.Path.Type, gatewayapi.HTTPRouteFilterURLRewrite)
}
}

func generateRequestTransformerForURLRewriteHostname(
filter *gatewayapi.HTTPURLRewriteFilter,
) kong.Plugin {
return kong.Plugin{
Name: kong.String("request-transformer"),
Config: kong.Configuration{
"replace": map[string]string{
"host": string(*filter.Hostname),
},
},
}
}

// generateRequestTransformerForURLRewriteFullPath generates a request-transformer plugin for the URLRewrite filter
Expand Down
95 changes: 68 additions & 27 deletions internal/dataplane/translator/subtranslator/httproute_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package subtranslator

import (
"errors"
"fmt"
"testing"

"github.com/kong/go-kong/kong"
Expand Down Expand Up @@ -292,7 +291,7 @@ func TestGenerateRequestTransformerForURLRewrite(t *testing.T) {
modifier *gatewayapi.HTTPURLRewriteFilter
firstMatchPath string
expectedKongRouteModification kongstate.Route
expected kong.Plugin
expected []kong.Plugin
expectedErr error
}{
{
Expand All @@ -303,14 +302,14 @@ func TestGenerateRequestTransformerForURLRewrite(t *testing.T) {
ReplaceFullPath: lo.ToPtr("/new-path"),
},
},
expected: kong.Plugin{
expected: []kong.Plugin{{
Name: lo.ToPtr("request-transformer"),
Config: kong.Configuration{
"replace": map[string]string{
"uri": "/new-path",
},
},
},
}},
expectedErr: nil,
},
{
Expand All @@ -322,14 +321,14 @@ func TestGenerateRequestTransformerForURLRewrite(t *testing.T) {
},
},
firstMatchPath: "/prefix",
expected: kong.Plugin{
expected: []kong.Plugin{{
Name: lo.ToPtr("request-transformer"),
Config: kong.Configuration{
"replace": map[string]string{
"uri": "/new$(uri_captures[1])",
},
},
},
}},
expectedKongRouteModification: kongstate.Route{
Route: kong.Route{
Paths: []*string{
Expand All @@ -348,14 +347,14 @@ func TestGenerateRequestTransformerForURLRewrite(t *testing.T) {
},
},
firstMatchPath: "/prefix",
expected: kong.Plugin{
expected: []kong.Plugin{{
Name: lo.ToPtr("request-transformer"),
Config: kong.Configuration{
"replace": map[string]string{
"uri": `$(uri_captures[1] == nil and "/" or uri_captures[1])`,
},
},
},
}},
expectedKongRouteModification: kongstate.Route{
Route: kong.Route{
Paths: []*string{
Expand All @@ -374,14 +373,14 @@ func TestGenerateRequestTransformerForURLRewrite(t *testing.T) {
},
},
firstMatchPath: "",
expected: kong.Plugin{
expected: []kong.Plugin{{
Name: lo.ToPtr("request-transformer"),
Config: kong.Configuration{
"replace": map[string]string{
"uri": `/prefix$(uri_captures[1] == nil and "" or "/" .. uri_captures[1])`,
},
},
},
}},
expectedKongRouteModification: kongstate.Route{
Route: kong.Route{
Paths: []*string{
Expand All @@ -400,14 +399,14 @@ func TestGenerateRequestTransformerForURLRewrite(t *testing.T) {
},
},
firstMatchPath: "/prefix",
expected: kong.Plugin{
expected: []kong.Plugin{{
Name: lo.ToPtr("request-transformer"),
Config: kong.Configuration{
"replace": map[string]string{
"uri": `$(uri_captures[1] == nil and "/" or uri_captures[1])`,
},
},
},
}},
expectedKongRouteModification: kongstate.Route{
Route: kong.Route{
Paths: []*string{
Expand All @@ -426,14 +425,14 @@ func TestGenerateRequestTransformerForURLRewrite(t *testing.T) {
},
},
firstMatchPath: "/",
expected: kong.Plugin{
expected: []kong.Plugin{{
Name: lo.ToPtr("request-transformer"),
Config: kong.Configuration{
"replace": map[string]string{
"uri": `$(uri_captures[1] == nil and "/" or "/" .. uri_captures[1])`,
},
},
},
}},
expectedKongRouteModification: kongstate.Route{
Route: kong.Route{
Paths: []*string{
Expand All @@ -452,14 +451,14 @@ func TestGenerateRequestTransformerForURLRewrite(t *testing.T) {
},
},
firstMatchPath: "/",
expected: kong.Plugin{
expected: []kong.Plugin{{
Name: lo.ToPtr("request-transformer"),
Config: kong.Configuration{
"replace": map[string]string{
"uri": `/new-prefix$(uri_captures[1] == nil and "" or "/" .. uri_captures[1])`,
},
},
},
}},
expectedKongRouteModification: kongstate.Route{
Route: kong.Route{
Paths: []*string{
Expand All @@ -478,14 +477,14 @@ func TestGenerateRequestTransformerForURLRewrite(t *testing.T) {
},
},
firstMatchPath: "/prefix/",
expected: kong.Plugin{
expected: []kong.Plugin{{
Name: lo.ToPtr("request-transformer"),
Config: kong.Configuration{
"replace": map[string]string{
"uri": `/new-prefix$(uri_captures[1])`,
},
},
},
}},
expectedKongRouteModification: kongstate.Route{
Route: kong.Route{
Paths: []*string{
Expand All @@ -495,31 +494,73 @@ func TestGenerateRequestTransformerForURLRewrite(t *testing.T) {
},
},
},
// TODO: https://github.com/Kong/kubernetes-ingress-controller/issues/3685
{
name: "valid URLRewriteFilter with unsupported",
name: "URLRewriteFilter with hostname",
modifier: &gatewayapi.HTTPURLRewriteFilter{
Hostname: lo.ToPtr(gatewayapi.PreciseHostname("hostname")),
Hostname: lo.ToPtr(gatewayapi.PreciseHostname("replaced.host")),
},
expected: []kong.Plugin{{
Name: lo.ToPtr("request-transformer"),
Config: kong.Configuration{
"replace": map[string]string{
"host": "replaced.host",
},
},
}},
},
{
name: "URLRewriteFilter with hostname and path",
modifier: &gatewayapi.HTTPURLRewriteFilter{
Path: &gatewayapi.HTTPPathModifier{
Type: gatewayapi.PrefixMatchHTTPPathModifier,
ReplacePrefixMatch: lo.ToPtr("/new-prefix"),
},
Hostname: lo.ToPtr(gatewayapi.PreciseHostname("replaced.host")),
},
firstMatchPath: "/prefix",
expected: []kong.Plugin{
{
Name: lo.ToPtr("request-transformer"),
Config: kong.Configuration{
"replace": map[string]string{
"uri": `/new-prefix$(uri_captures[1])`,
},
},
},
{
Name: lo.ToPtr("request-transformer"),
Config: kong.Configuration{
"replace": map[string]string{
"host": "replaced.host",
},
},
},
},
expectedKongRouteModification: kongstate.Route{
Route: kong.Route{
Paths: []*string{
lo.ToPtr("~/prefix$"),
lo.ToPtr("~/prefix(/.*)"),
},
},
},
expected: kong.Plugin{},
expectedErr: fmt.Errorf("unsupported hostname replace for %s", gatewayapi.HTTPRouteFilterURLRewrite),
},
{
name: "nil URLRewriteFilter",
modifier: nil,
expected: kong.Plugin{},
expected: nil,
expectedErr: errors.New("URLRewrite is not provided"),
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
plugin, routeModifier, err := generateRequestTransformerForURLRewrite(tc.modifier, tc.firstMatchPath, false)
plugins, routeModifiers, err := generateRequestTransformerForURLRewrite(tc.modifier, tc.firstMatchPath, false)
require.Equal(t, tc.expectedErr, err)
require.Equal(t, tc.expected, plugin)
require.Equal(t, tc.expected, plugins)

route := kongstate.Route{}
if routeModifier != nil {
for _, routeModifier := range routeModifiers {
routeModifier(&route)
}
require.Equal(t, tc.expectedKongRouteModification, route)
Expand Down
2 changes: 2 additions & 0 deletions test/conformance/gateway_conformance_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ var traditionalRoutesSupportedFeatures = []suite.SupportedFeature{
// extended features
suite.SupportHTTPRouteResponseHeaderModification,
suite.SupportHTTPRoutePathRewrite,
suite.SupportHTTPRouteHostRewrite,
// TODO: https://github.com/Kong/kubernetes-ingress-controller/issues/5868
// Temporarily disabled and tracking through the following issue.
// suite.SupportHTTPRouteBackendTimeout,
Expand All @@ -46,6 +47,7 @@ var expressionRoutesSupportedFeatures = []suite.SupportedFeature{
suite.SupportHTTPRouteMethodMatching,
suite.SupportHTTPRouteResponseHeaderModification,
suite.SupportHTTPRoutePathRewrite,
suite.SupportHTTPRouteHostRewrite,
// TODO: https://github.com/Kong/kubernetes-ingress-controller/issues/5868
// Temporarily disabled and tracking through the following issue.
// suite.SupportHTTPRouteBackendTimeout,
Expand Down

0 comments on commit 45546f1

Please sign in to comment.