Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions api/dashboard/v1/plugin_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,8 @@ type WolfRBACConsumerConfig struct {
type RewriteConfig struct {
RewriteTarget string `json:"uri,omitempty"`
RewriteTargetRegex []string `json:"regex_uri,omitempty"`
Headers Headers `json:"headers,omitempty"`
Headers *Headers `json:"headers,omitempty"`
Host string `json:"host,omitempty"`
}

// ResponseRewriteConfig is the rule config for response-rewrite plugin.
Expand All @@ -152,7 +153,7 @@ type ResponseRewriteConfig struct {
StatusCode int `json:"status_code,omitempty"`
Body string `json:"body,omitempty"`
BodyBase64 bool `json:"body_base64,omitempty"`
Headers ResponseHeaders `json:"headers,omitempty"`
Headers *ResponseHeaders `json:"headers,omitempty"`
LuaRestyExpr []expr.Expr `json:"vars,omitempty"`
Filters []map[string]string `json:"filters,omitempty"`
}
Expand Down
12 changes: 10 additions & 2 deletions api/dashboard/v1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

52 changes: 43 additions & 9 deletions internal/controlplane/translator/httproute.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,7 @@ import (
"github.com/api7/api7-ingress-controller/internal/id"
)

const (
RequestMirror = "proxy-mirror"
)

func (t *Translator) fillPluginsFromHTTPRouteFilters(plugins v1.Plugins, namespace string, filters []gatewayv1.HTTPRouteFilter) {
func (t *Translator) fillPluginsFromHTTPRouteFilters(plugins v1.Plugins, namespace string, filters []gatewayv1.HTTPRouteFilter, matches []gatewayv1.HTTPRouteMatch) {
for _, filter := range filters {
switch filter.Type {
case gatewayv1.HTTPRouteFilterRequestHeaderModifier:
Expand All @@ -28,20 +24,58 @@ func (t *Translator) fillPluginsFromHTTPRouteFilters(plugins v1.Plugins, namespa
case gatewayv1.HTTPRouteFilterRequestMirror:
t.fillPluginFromHTTPRequestMirrorFilter(namespace, plugins, filter.RequestMirror)
case gatewayv1.HTTPRouteFilterURLRewrite:
// TODO: Supported, to be implemented
t.fillPluginFromURLRewriteFilter(plugins, filter.URLRewrite, matches)
case gatewayv1.HTTPRouteFilterResponseHeaderModifier:
t.fillPluginFromHTTPResponseHeaderFilter(plugins, filter.ResponseHeaderModifier)
}
}
}

func (t *Translator) fillPluginFromURLRewriteFilter(plugins v1.Plugins, urlRewrite *gatewayv1.HTTPURLRewriteFilter, matches []gatewayv1.HTTPRouteMatch) {
pluginName := v1.PluginProxyRewrite
obj := plugins[pluginName]
var plugin *v1.RewriteConfig
if obj == nil {
plugin = &v1.RewriteConfig{}
plugins[pluginName] = plugin
} else {
plugin = obj.(*v1.RewriteConfig)
}
if urlRewrite.Hostname != nil {
plugin.Host = string(*urlRewrite.Hostname)
}

if urlRewrite.Path != nil {
switch urlRewrite.Path.Type {
case gatewayv1.FullPathHTTPPathModifier:
plugin.RewriteTarget = *urlRewrite.Path.ReplaceFullPath
case gatewayv1.PrefixMatchHTTPPathModifier:
prefixPaths := make([]string, 0, len(matches))
for _, match := range matches {
if match.Path == nil || match.Path.Type == nil || *match.Path.Type != gatewayv1.PathMatchPathPrefix {
continue
}
prefixPaths = append(prefixPaths, *match.Path.Value)
}
regexPattern := "^(" + strings.Join(prefixPaths, "|") + ")" + "/(.*)"
replaceTarget := *urlRewrite.Path.ReplacePrefixMatch
regexTarget := replaceTarget + "/$2"

plugin.RewriteTargetRegex = []string{
regexPattern,
regexTarget,
}
}
}
}

func (t *Translator) fillPluginFromHTTPRequestHeaderFilter(plugins v1.Plugins, reqHeaderModifier *gatewayv1.HTTPHeaderFilter) {
pluginName := v1.PluginProxyRewrite
obj := plugins[pluginName]
var plugin *v1.RewriteConfig
if obj == nil {
plugin = &v1.RewriteConfig{
Headers: v1.Headers{
Headers: &v1.Headers{
Add: make(map[string]string, len(reqHeaderModifier.Add)),
Set: make(map[string]string, len(reqHeaderModifier.Set)),
Remove: make([]string, 0, len(reqHeaderModifier.Remove)),
Expand Down Expand Up @@ -72,7 +106,7 @@ func (t *Translator) fillPluginFromHTTPResponseHeaderFilter(plugins v1.Plugins,
var plugin *v1.ResponseRewriteConfig
if obj == nil {
plugin = &v1.ResponseRewriteConfig{
Headers: v1.ResponseHeaders{
Headers: &v1.ResponseHeaders{
Add: make([]string, 0, len(respHeaderModifier.Add)),
Set: make(map[string]string, len(respHeaderModifier.Set)),
Remove: make([]string, 0, len(respHeaderModifier.Remove)),
Expand Down Expand Up @@ -262,7 +296,7 @@ func (t *Translator) TranslateGatewayHTTPRoute(tctx *TranslateContext, httpRoute
service.ID = id.GenID(service.Name)
service.Labels = label.GenLabel(httpRoute)
service.Hosts = hosts
t.fillPluginsFromHTTPRouteFilters(service.Plugins, httpRoute.GetNamespace(), rule.Filters)
t.fillPluginsFromHTTPRouteFilters(service.Plugins, httpRoute.GetNamespace(), rule.Filters, rule.Matches)

result.Services = append(result.Services, service)

Expand Down
91 changes: 91 additions & 0 deletions test/e2e/gatewayapi/httproute.go
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,59 @@ spec:
statusCode: 301
`

var replacePrefixMatch = `
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: httpbin
spec:
parentRefs:
- name: api7ee
hostnames:
- httpbin.example
rules:
- matches:
- path:
type: PathPrefix
value: /replace
filters:
- type: URLRewrite
urlRewrite:
path:
type: ReplacePrefixMatch
replacePrefixMatch: /status
backendRefs:
- name: httpbin-service-e2e-test
port: 80
`

var replaceFullPathAndHost = `
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: httpbin
spec:
parentRefs:
- name: api7ee
hostnames:
- httpbin.example
rules:
- matches:
- path:
type: PathPrefix
value: /replace
filters:
- type: URLRewrite
urlRewrite:
hostname: replace.example.org
path:
type: ReplaceFullPath
replaceFullPath: /headers
backendRefs:
- name: httpbin-service-e2e-test
port: 80
`

BeforeEach(beforeEach)

It("HTTPRoute RequestHeaderModifier", func() {
Expand Down Expand Up @@ -502,6 +555,44 @@ spec:
echoLogs := s.GetDeploymentLogs("echo")
Expect(echoLogs).To(ContainSubstring("GET /headers"))
})

It("HTTPRoute URLRewrite with ReplaceFullPath And Hostname", func() {
By("create HTTPRoute")
ResourceApplied("HTTPRoute", "httpbin", replaceFullPathAndHost, 1)

By("/replace/201 should be rewritten to /headers")
s.NewAPISIXClient().GET("/replace/201").
WithHeader("Host", "httpbin.example").
Expect().
Status(http.StatusOK).
Body().
Contains("replace.example.org")

By("/replace/500 should be rewritten to /headers")
s.NewAPISIXClient().GET("/replace/500").
WithHeader("Host", "httpbin.example").
Expect().
Status(http.StatusOK).
Body().
Contains("replace.example.org")
})

It("HTTPRoute URLRewrite with ReplacePrefixMatch", func() {
By("create HTTPRoute")
ResourceApplied("HTTPRoute", "httpbin", replacePrefixMatch, 1)

By("/replace/201 should be rewritten to /status/201")
s.NewAPISIXClient().GET("/replace/201").
WithHeader("Host", "httpbin.example").
Expect().
Status(http.StatusCreated)

By("/replace/500 should be rewritten to /status/500")
s.NewAPISIXClient().GET("/replace/500").
WithHeader("Host", "httpbin.example").
Expect().
Status(http.StatusInternalServerError)
})
})

Context("HTTPRoute Multiple Backend", func() {
Expand Down
Loading