From 5c8e4a7df1d0be41d1acbe6cf100ffcbfd8377fb Mon Sep 17 00:00:00 2001 From: Toby Chui Date: Tue, 21 Oct 2025 07:52:07 +0800 Subject: [PATCH] Fixed priority sort logic for HTTP proxy rule Fixed proxy rule sort logic from alphabetical to best match --- src/mod/dynamicproxy/proxyRequestHandler.go | 25 +++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/src/mod/dynamicproxy/proxyRequestHandler.go b/src/mod/dynamicproxy/proxyRequestHandler.go index 35084e0..366dcc4 100644 --- a/src/mod/dynamicproxy/proxyRequestHandler.go +++ b/src/mod/dynamicproxy/proxyRequestHandler.go @@ -51,6 +51,11 @@ func (router *Router) GetProxyEndpointFromHostname(hostname string) *ProxyEndpoi matchProxyEndpoints := []*ProxyEndpoint{} router.ProxyEndpoints.Range(func(k, v interface{}) bool { ep := v.(*ProxyEndpoint) + if ep.Disabled { + //Skip disabled endpoint + return true + } + match, err := filepath.Match(ep.RootOrMatchingDomain, hostname) if err != nil { //Bad pattern. Skip this rule @@ -83,12 +88,24 @@ func (router *Router) GetProxyEndpointFromHostname(hostname string) *ProxyEndpoi }) if len(matchProxyEndpoints) == 1 { - //Only 1 match return matchProxyEndpoints[0] } else if len(matchProxyEndpoints) > 1 { - //More than one match. Get the best match one - sort.Slice(matchProxyEndpoints, func(i, j int) bool { - return matchProxyEndpoints[i].RootOrMatchingDomain < matchProxyEndpoints[j].RootOrMatchingDomain + // More than one match, pick one that is: + // 1. longer RootOrMatchingDomain (more specific) + // 2. fewer wildcard characters (* and ?) (more specific) + // 3. fallback to lexicographic order + sort.SliceStable(matchProxyEndpoints, func(i, j int) bool { + a := matchProxyEndpoints[i].RootOrMatchingDomain + b := matchProxyEndpoints[j].RootOrMatchingDomain + if len(a) != len(b) { + return len(a) > len(b) + } + aw := strings.Count(a, "*") + strings.Count(a, "?") + bw := strings.Count(b, "*") + strings.Count(b, "?") + if aw != bw { + return aw < bw + } + return a < b }) return matchProxyEndpoints[0] }