From c7cec75ac5ac1058401ffa89fb4c35667c153b18 Mon Sep 17 00:00:00 2001 From: rongxin Date: Tue, 26 May 2026 10:28:53 +0800 Subject: [PATCH] fix: set uris to ["/*"] when HTTPRoute path type is RegularExpression When path.type is RegularExpression, the controller sets route.Vars for regex matching but never sets route.Uris, leaving it nil. This serializes as "uris": null, which is rejected by APISIX Admin API v3 with HTTP 400 (expected array, received null). Omitting the field via omitempty also fails with "received undefined". The correct fix is to set uris to ["/*"] as a catch-all passthrough so APISIX accepts the route payload, while the vars entry performs the actual regex filtering against the request URI. Fixes #2764 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- internal/adc/translator/httproute.go | 4 +++ test/e2e/gatewayapi/httproute.go | 54 ++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/internal/adc/translator/httproute.go b/internal/adc/translator/httproute.go index 4acabd31..fb6cf707 100644 --- a/internal/adc/translator/httproute.go +++ b/internal/adc/translator/httproute.go @@ -741,6 +741,10 @@ func (t *Translator) translateGatewayHTTPRouteMatch(match *gatewayv1.HTTPRouteMa }) route.Vars = append(route.Vars, this) + // APISIX Admin API requires uris to be a non-null array. Use "/*" + // as a catch-all so APISIX accepts the route; the vars entry above + // performs the actual regex filtering. + route.Uris = []string{"/*"} default: return nil, errors.New("unknown path match type " + string(*match.Path.Type)) } diff --git a/test/e2e/gatewayapi/httproute.go b/test/e2e/gatewayapi/httproute.go index 75197a29..e9432002 100644 --- a/test/e2e/gatewayapi/httproute.go +++ b/test/e2e/gatewayapi/httproute.go @@ -942,6 +942,60 @@ spec: }) }) + It("HTTPRoute RegularExpression Match", func() { + var regexRoute = fmt.Sprintf(` +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: httpbin +spec: + parentRefs: + - name: %s + hostnames: + - httpbin.example + rules: + - matches: + - path: + type: RegularExpression + value: /status/[0-9]+ + backendRefs: + - name: httpbin-service-e2e-test + port: 80 +`, s.Namespace()) + + By("create HTTPRoute with RegularExpression path type") + s.ResourceApplied("HTTPRoute", "httpbin", regexRoute, 1) + + By("access dataplane: path matching regex should succeed") + s.RequestAssert(&scaffold.RequestAssert{ + Method: "GET", + Path: "/status/200", + Host: "httpbin.example", + Check: scaffold.WithExpectedStatus(http.StatusOK), + Timeout: time.Second * 30, + Interval: time.Second * 2, + }) + + s.RequestAssert(&scaffold.RequestAssert{ + Method: "GET", + Path: "/status/201", + Host: "httpbin.example", + Check: scaffold.WithExpectedStatus(http.StatusCreated), + Timeout: time.Second * 30, + Interval: time.Second * 2, + }) + + By("access dataplane: path not matching regex should return 404") + s.RequestAssert(&scaffold.RequestAssert{ + Method: "GET", + Path: "/status/ok", + Host: "httpbin.example", + Check: scaffold.WithExpectedStatus(http.StatusNotFound), + Timeout: time.Second * 30, + Interval: time.Second * 2, + }) + }) + It("HTTPRoute Method Match", func() { By("create HTTPRoute") s.ResourceApplied("HTTPRoute", "httpbin", fmt.Sprintf(methodRouteGETAndDELETEByAnything, s.Namespace()), 1)