You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@apisix.apache.org by al...@apache.org on 2025/09/05 02:44:50 UTC

(apisix-ingress-controller) branch master updated: fix: responseHeaderModifier fails to synchronize (#2544)

This is an automated email from the ASF dual-hosted git repository.

alinsran pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix-ingress-controller.git


The following commit(s) were added to refs/heads/master by this push:
     new f1724106 fix: responseHeaderModifier fails to synchronize (#2544)
f1724106 is described below

commit f17241061700893ba0d196964780c3f2b8f137d1
Author: AlinsRan <al...@apache.org>
AuthorDate: Fri Sep 5 10:44:45 2025 +0800

    fix: responseHeaderModifier fails to synchronize (#2544)
---
 api/adc/types.go                 |   6 +--
 test/e2e/gatewayapi/httproute.go | 113 +++++++++++++++++++++++++++++++++++++--
 test/e2e/scaffold/assertion.go   |  22 ++++++++
 3 files changed, 135 insertions(+), 6 deletions(-)

diff --git a/api/adc/types.go b/api/adc/types.go
index 618fb3ce..db4d2d71 100644
--- a/api/adc/types.go
+++ b/api/adc/types.go
@@ -635,9 +635,9 @@ type ResponseRewriteConfig struct {
 }
 
 type ResponseHeaders struct {
-	Set    map[string]string `json:"set" yaml:"set"`
-	Add    []string          `json:"add" yaml:"add"`
-	Remove []string          `json:"remove" yaml:"remove"`
+	Set    map[string]string `json:"set,omitempty" yaml:"set,omitempty"`
+	Add    []string          `json:"add,omitempty" yaml:"add,omitempty"`
+	Remove []string          `json:"remove,omitempty" yaml:"remove,omitempty"`
 }
 
 // RequestMirror is the rule config for proxy-mirror plugin.
diff --git a/test/e2e/gatewayapi/httproute.go b/test/e2e/gatewayapi/httproute.go
index 77b50849..2ee93beb 100644
--- a/test/e2e/gatewayapi/httproute.go
+++ b/test/e2e/gatewayapi/httproute.go
@@ -1444,6 +1444,82 @@ spec:
       port: 80
 `
 
+		var respHeaderModifyWithAdd = `
+apiVersion: gateway.networking.k8s.io/v1
+kind: HTTPRoute
+metadata:
+  name: add
+spec:
+  parentRefs:
+  - name: %s
+  hostnames:
+  - httpbin.example.resp-header-modify.add
+  rules:
+  - matches: 
+    - path:
+        type: Exact
+        value: /headers
+    filters:
+    - type: ResponseHeaderModifier
+      responseHeaderModifier:
+        add:
+        - name: X-Resp-Add
+          value: "resp-add"
+    backendRefs:
+    - name: httpbin-service-e2e-test
+      port: 80
+`
+
+		var respHeaderModifyWithSet = `
+apiVersion: gateway.networking.k8s.io/v1
+kind: HTTPRoute
+metadata:
+  name: set
+spec:
+  parentRefs:
+  - name: %s
+  hostnames:
+  - httpbin.example.resp-header-modify.set
+  rules:
+  - matches: 
+    - path:
+        type: Exact
+        value: /headers
+    filters:
+    - type: ResponseHeaderModifier
+      responseHeaderModifier:
+        set:
+        - name: X-Resp-Set
+          value: "resp-set"
+    backendRefs:
+    - name: httpbin-service-e2e-test
+      port: 80
+`
+
+		var respHeaderModifyWithRemove = `
+apiVersion: gateway.networking.k8s.io/v1
+kind: HTTPRoute
+metadata:
+  name: remove
+spec:
+  parentRefs:
+  - name: %s
+  hostnames:
+  - httpbin.example.resp-header-modify.remove
+  rules:
+  - matches: 
+    - path:
+        type: Exact
+        value: /headers
+    filters:
+    - type: ResponseHeaderModifier
+      responseHeaderModifier:
+        remove:
+        - Server
+    backendRefs:
+    - name: httpbin-service-e2e-test
+      port: 80
+`
 		var respHeaderModifyByHeaders = `
 apiVersion: gateway.networking.k8s.io/v1
 kind: HTTPRoute
@@ -1655,6 +1731,9 @@ spec:
 		It("HTTPRoute ResponseHeaderModifier", func() {
 			By("create HTTPRoute")
 			s.ResourceApplied("HTTPRoute", "httpbin", fmt.Sprintf(respHeaderModifyByHeaders, s.Namespace(), s.Namespace()), 1)
+			s.ResourceApplied("HTTPRoute", "add", fmt.Sprintf(respHeaderModifyWithAdd, s.Namespace()), 1)
+			s.ResourceApplied("HTTPRoute", "set", fmt.Sprintf(respHeaderModifyWithSet, s.Namespace()), 1)
+			s.ResourceApplied("HTTPRoute", "remove", fmt.Sprintf(respHeaderModifyWithRemove, s.Namespace()), 1)
 
 			By("access daataplane to check the HTTPRoute")
 			s.RequestAssert(&scaffold.RequestAssert{
@@ -1666,12 +1745,40 @@ spec:
 					scaffold.WithExpectedHeaders(map[string]string{
 						"X-Resp-Add": "add",
 						"X-Resp-Set": "set",
-						"Server":     "",
 					}),
+					scaffold.WithExpectedNotHeader("Server"),
 					scaffold.WithExpectedBodyNotContains(`"X-Resp-Add": "add"`, `"X-Resp-Set": "set"`, `"Server"`),
 				},
-				Timeout:  time.Second * 30,
-				Interval: time.Second * 2,
+			})
+			s.RequestAssert(&scaffold.RequestAssert{
+				Method: "GET",
+				Path:   "/headers",
+				Host:   "httpbin.example.resp-header-modify.add",
+				Checks: []scaffold.ResponseCheckFunc{
+					scaffold.WithExpectedStatus(http.StatusOK),
+					scaffold.WithExpectedHeader("X-Resp-Add", "resp-add"),
+					scaffold.WithExpectedBodyNotContains(`"X-Resp-Add": "resp-add"`),
+				},
+			})
+			s.RequestAssert(&scaffold.RequestAssert{
+				Method: "GET",
+				Path:   "/headers",
+				Host:   "httpbin.example.resp-header-modify.set",
+				Checks: []scaffold.ResponseCheckFunc{
+					scaffold.WithExpectedStatus(http.StatusOK),
+					scaffold.WithExpectedHeader("X-Resp-Set", "resp-set"),
+					scaffold.WithExpectedBodyNotContains(`"Server"`),
+				},
+			})
+			s.RequestAssert(&scaffold.RequestAssert{
+				Method: "GET",
+				Path:   "/headers",
+				Host:   "httpbin.example.resp-header-modify.remove",
+				Checks: []scaffold.ResponseCheckFunc{
+					scaffold.WithExpectedStatus(http.StatusOK),
+					scaffold.WithExpectedNotHeader("Server"),
+					scaffold.WithExpectedBodyNotContains(`"Server"`),
+				},
 			})
 		})
 
diff --git a/test/e2e/scaffold/assertion.go b/test/e2e/scaffold/assertion.go
index ef2c35eb..30c8cd8e 100644
--- a/test/e2e/scaffold/assertion.go
+++ b/test/e2e/scaffold/assertion.go
@@ -149,6 +149,28 @@ func WithExpectedHeaders(expectedHeaders map[string]string) ResponseCheckFunc {
 	}
 }
 
+func WithExpectedNotHeader(key string) ResponseCheckFunc {
+	return func(resp *HTTPResponse) error {
+		if resp.Header.Get(key) != "" {
+			return fmt.Errorf("expected header %q to be empty, but got %q",
+				key, resp.Header.Get(key))
+		}
+		return nil
+	}
+}
+
+func WithExpectedNotHeaders(unexpectedHeaders []string) ResponseCheckFunc {
+	return func(resp *HTTPResponse) error {
+		for _, key := range unexpectedHeaders {
+			if resp.Header.Get(key) != "" {
+				return fmt.Errorf("expected header %q to be empty, but got %q",
+					key, resp.Header.Get(key))
+			}
+		}
+		return nil
+	}
+}
+
 func (s *Scaffold) RequestAssert(r *RequestAssert) bool {
 	if r.Client == nil {
 		r.Client = s.NewAPISIXClient()