feat: add annotation to allow to add custom response headers (#9742)

* add custom headers

Signed-off-by: Christian Groschupp <christian@groschupp.org>

* add tests

Signed-off-by: Christian Groschupp <christian@groschupp.org>

* add docs

* update copyright

* change comments

* add e2e test customheaders

* add custom headers validation

* remove escapeLiteralDollar filter

* validate value in custom headers

* add regex for header value

* fix annotation test

* Revert "remove escapeLiteralDollar filter"

This reverts commit ab48392b60dee4ce146a4c17e046849f9633c7fb.

* add annotationConfig

* fix test

* fix golangci-lint findings

* fix: add missung exp module

---------

Signed-off-by: Christian Groschupp <christian@groschupp.org>
This commit is contained in:
Christian Groschupp 2024-04-09 12:25:22 +02:00 committed by GitHub
parent d56aacdb31
commit 1f4ee0e235
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 537 additions and 4 deletions

View file

@ -43,16 +43,20 @@ var (
annotationAffinityCookieName = parser.GetAnnotationWithPrefix("session-cookie-name")
annotationUpstreamHashBy = parser.GetAnnotationWithPrefix("upstream-hash-by")
annotationCustomHTTPErrors = parser.GetAnnotationWithPrefix("custom-http-errors")
annotationCustomHeaders = parser.GetAnnotationWithPrefix("custom-headers")
)
type mockCfg struct {
resolver.Mock
MockSecrets map[string]*apiv1.Secret
MockServices map[string]*apiv1.Service
MockSecrets map[string]*apiv1.Secret
MockServices map[string]*apiv1.Service
MockConfigMaps map[string]*apiv1.ConfigMap
}
func (m mockCfg) GetDefaultBackend() defaults.Backend {
return defaults.Backend{}
return defaults.Backend{
AllowedResponseHeaders: []string{"Content-Type"},
}
}
func (m mockCfg) GetSecret(name string) (*apiv1.Secret, error) {
@ -63,6 +67,10 @@ func (m mockCfg) GetService(name string) (*apiv1.Service, error) {
return m.MockServices[name], nil
}
func (m mockCfg) GetConfigMap(name string) (*apiv1.ConfigMap, error) {
return m.MockConfigMaps[name], nil
}
func (m mockCfg) GetAuthCertificate(name string) (*resolver.AuthSSLCert, error) {
secret, err := m.GetSecret(name)
if err != nil {
@ -317,3 +325,44 @@ func TestCustomHTTPErrors(t *testing.T) {
}
}
}
func TestCustomResponseHeaders(t *testing.T) {
mockObj := mockCfg{}
mockObj.MockConfigMaps = map[string]*apiv1.ConfigMap{}
mockObj.MockConfigMaps["custom-headers"] = &apiv1.ConfigMap{Data: map[string]string{"Content-Type": "application/json"}}
mockObj.MockConfigMaps["empty-custom-headers"] = &apiv1.ConfigMap{Data: map[string]string{}}
ec := NewAnnotationExtractor(mockObj)
ing := buildIngress()
fooAnns := []struct {
annotations map[string]string
headers map[string]string
}{
{map[string]string{annotationCustomHeaders: "custom-headers"}, map[string]string{"Content-Type": "application/json"}},
{map[string]string{annotationCustomHeaders: "empty-custom-headers"}, map[string]string{}},
{nil, map[string]string{}},
}
for _, foo := range fooAnns {
ing.SetAnnotations(foo.annotations)
rann, err := ec.Extract(ing)
if err != nil {
t.Errorf("error should be null: %v", err)
}
r := rann.CustomHeaders.Headers
// Check that expected headers were created
for i := range foo.headers {
if r[i] != foo.headers[i] {
t.Errorf("Returned %v but expected %v", r, foo.headers)
}
}
// Check that no unexpected headers were created
for i := range r {
if r[i] != foo.headers[i] {
t.Errorf("Returned %v but expected %v", r, foo.headers)
}
}
}
}