Skip to content

Commit

Permalink
feat: Add Rewrite Header Annotations
Browse files Browse the repository at this point in the history
  • Loading branch information
MatthiasMpo committed Aug 26, 2024
1 parent fee11af commit c6eb07d
Show file tree
Hide file tree
Showing 5 changed files with 167 additions and 1 deletion.
27 changes: 27 additions & 0 deletions docs/en/latest/concepts/annotations.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,33 @@ spec:
number: 80
```

### Rewrite Headers

### Add header

This annotation configures to append the new headers in the upstream request.

```yaml
k8s.apisix.apache.org/rewrite-add-header: "testkey1:testval1,testkey2:testval2"
```

### Set header

This annotation configures to rewrite the new headers in the upstream request.

```yaml
k8s.apisix.apache.org/rewrite-set-header: "testkey1:testval1,testkey2:testval2"
```

### Remove header

This annotation configures to remove headers in the upstream request.

```yaml
k8s.apisix.apache.org/rewrite-remove-header: "testkey1,testkey2"
```


## HTTP to HTTPS

This annotation is used to redirect HTTP requests to HTTPS with a `301` status code and with the same URI as the original request.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,15 @@ func (i *rewrite) Handle(e annotations.Extractor) (interface{}, error) {
rewriteTarget := e.GetStringAnnotation(annotations.AnnotationsRewriteTarget)
rewriteTargetRegex := e.GetStringAnnotation(annotations.AnnotationsRewriteTargetRegex)
rewriteTemplate := e.GetStringAnnotation(annotations.AnnotationsRewriteTargetRegexTemplate)
if rewriteTarget != "" || rewriteTargetRegex != "" || rewriteTemplate != "" {

headers := make(apisixv1.Headers)
headers.Add(e.GetStringsAnnotation(annotations.AnnotationsRewriteHeaderAdd))
headers.Set(e.GetStringsAnnotation(annotations.AnnotationsRewriteHeaderSet))
headers.Remove(e.GetStringsAnnotation(annotations.AnnotationsRewriteHeaderRemove))

if rewriteTarget != "" || rewriteTargetRegex != "" || rewriteTemplate != "" || len(headers) > 0 {
plugin.RewriteTarget = rewriteTarget
plugin.Headers = headers
if rewriteTargetRegex != "" && rewriteTemplate != "" {
_, err := regexp.Compile(rewriteTargetRegex)
if err != nil {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Licensed to the Apache Software Foundation (ASF) under one or more
// contributor license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright ownership.
// The ASF licenses this file to You under the Apache License, Version 2.0
// (the "License"); you may not use this file except in compliance with
// the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package plugins

import (
"testing"

"github.com/stretchr/testify/assert"

"github.com/apache/apisix-ingress-controller/pkg/providers/ingress/translation/annotations"
apisixv1 "github.com/apache/apisix-ingress-controller/pkg/types/apisix/v1"
)

func TestRewriteHandler(t *testing.T) {
anno := map[string]string{
annotations.AnnotationsRewriteTarget: "/sample",
annotations.AnnotationsRewriteTargetRegex: "/sample/(.*)",
annotations.AnnotationsRewriteTargetRegexTemplate: "/$1",
annotations.AnnotationsRewriteHeaderAdd: "testkey1:testval1,testkey2:testval2",
annotations.AnnotationsRewriteHeaderRemove: "testkey1,testkey2",
annotations.AnnotationsRewriteHeaderSet: "testkey1:testval1,testkey2:testval2",
}
p := NewRewriteHandler()
out, err := p.Handle(annotations.NewExtractor(anno))
assert.Nil(t, err, "checking given error")
config := out.(*apisixv1.RewriteConfig)
assert.Equal(t, "/sample", config.RewriteTarget)
assert.Equal(t, []string{"/sample/(.*)", "/$1"}, config.RewriteTargetRegex)
assert.Equal(t, "proxy-rewrite", p.PluginName())
assert.Equal(t, []string{"testkey1:testval1", "testkey2:testval2"}, config.Headers.GetAddedHeaders())
assert.Equal(t, []string{"testkey1", "testkey2"}, config.Headers.GetRemovedHeaders())
assert.Equal(t, map[string]string{
"testkey1": "testval1",
"testkey2": "testval2",
}, config.Headers.GetSetHeaders())
}
3 changes: 3 additions & 0 deletions pkg/providers/ingress/translation/annotations/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ const (
AnnotationsRewriteTarget = AnnotationsPrefix + "rewrite-target"
AnnotationsRewriteTargetRegex = AnnotationsPrefix + "rewrite-target-regex"
AnnotationsRewriteTargetRegexTemplate = AnnotationsPrefix + "rewrite-target-regex-template"
AnnotationsRewriteHeaderAdd = AnnotationsPrefix + "rewrite-add-header"
AnnotationsRewriteHeaderSet = AnnotationsPrefix + "rewrite-set-header"
AnnotationsRewriteHeaderRemove = AnnotationsPrefix + "rewrite-remove-header"

// response-rewrite plugin
AnnotationsEnableResponseRewrite = AnnotationsPrefix + "enable-response-rewrite"
Expand Down
81 changes: 81 additions & 0 deletions test/e2e/suite-annotations/rewrite.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,3 +154,84 @@ spec:
_ = s.NewAPISIXClient().GET("/sample/get").WithHeader("Host", "httpbin.org").Expect().Status(http.StatusOK)
})
})

var _ = ginkgo.Describe("suite-annotations: rewrite header annotations", func() {
s := scaffold.NewDefaultScaffold()

ginkgo.It("enable in ingress networking/v1", func() {
backendSvc, backendPort := s.DefaultHTTPBackend()
ing := fmt.Sprintf(`
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: apisix
k8s.apisix.apache.org/rewrite-target-regex: "/sample/(.*)"
k8s.apisix.apache.org/rewrite-target-regex-template: "/$1"
k8s.apisix.apache.org/rewrite-add-header: "X-Api-Version:v1;X-Api-Engine:Apisix"
k8s.apisix.apache.org/rewrite-set-header: "X-Request-ID:123"
k8s.apisix.apache.org/rewrite-remove-header: "X-Test"
name: ingress-v1
spec:
rules:
- host: httpbin.org
http:
paths:
- path: /sample
pathType: Prefix
backend:
service:
name: %s
port:
number: %d
`, backendSvc, backendPort[0])
err := s.CreateResourceFromString(ing)
assert.Nil(ginkgo.GinkgoT(), err, "creating ingress")
time.Sleep(5 * time.Second)

resp := s.NewAPISIXClient().GET("/sample/ip").WithHeader("Host", "httpbin.org").WithHeader("X-Request-ID", "000").WithHeader("X-Test", "Test").Expect()
resp.Status(http.StatusOK)
resp.Header("X-Api-Version").IsEqual("v1")
resp.Header("X-Api-Engine").IsEqual("Apisix")
resp.Header("X-Request-ID").IsEqual("123")
resp.Header("X-Test").IsEmpty()
})
ginkgo.It("enable in ingress networking/v1beta1", func() {
backendSvc, backendPort := s.DefaultHTTPBackend()
ing := fmt.Sprintf(`
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: apisix
k8s.apisix.apache.org/rewrite-target-regex: "/sample/(.*)"
k8s.apisix.apache.org/rewrite-target-regex-template: "/$1"
k8s.apisix.apache.org/rewrite-add-header: "X-Api-Version:v1;X-Api-Engine:Apisix"
k8s.apisix.apache.org/rewrite-set-header: "X-Request-ID:123"
k8s.apisix.apache.org/rewrite-remove-header: "X-Test"
name: ingress-v1
spec:
rules:
- host: httpbin.org
http:
paths:
- path: /sample
pathType: Prefix
backend:
service:
name: %s
port:
number: %d
`, backendSvc, backendPort[0])
err := s.CreateResourceFromString(ing)
assert.Nil(ginkgo.GinkgoT(), err, "creating ingress")
time.Sleep(5 * time.Second)

resp := s.NewAPISIXClient().GET("/sample/ip").WithHeader("Host", "httpbin.org").WithHeader("X-Request-ID", "000").WithHeader("X-Test", "Test").Expect()
resp.Status(http.StatusOK)
resp.Header("X-Api-Version").IsEqual("v1")
resp.Header("X-Api-Engine").IsEqual("Apisix")
resp.Header("X-Request-ID").IsEqual("123")
resp.Header("X-Test").IsEmpty()
})
})

0 comments on commit c6eb07d

Please sign in to comment.