feat: add zero-cost wildcard prefix matching for Proxy and Rewrite routes (by AI)
This commit is contained in:
parent
2b7e11e7d2
commit
3cde76a6b0
20
config.go
20
config.go
@ -2,8 +2,6 @@ package service
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// CertSet SSL 证书配置
|
||||
@ -90,14 +88,7 @@ func ApplyConfig() {
|
||||
}
|
||||
newProxies := make([]*proxyType, 0, len(rules))
|
||||
for _, r := range rules {
|
||||
p := &proxyType{authLevel: r.AuthLevel, fromPath: r.Path, toApp: r.ToApp, toPath: r.ToPath}
|
||||
if strings.ContainsRune(r.Path, '(') {
|
||||
matcher, err := regexp.Compile("^" + r.Path + "$")
|
||||
if err == nil {
|
||||
p.matcher = matcher
|
||||
}
|
||||
}
|
||||
newProxies = append(newProxies, p)
|
||||
newProxies = append(newProxies, parseProxyRule(r.AuthLevel, r.Path, r.ToApp, r.ToPath))
|
||||
}
|
||||
fileProxies[host] = newProxies
|
||||
rebuildProxiesUnderLock(host)
|
||||
@ -109,14 +100,7 @@ func ApplyConfig() {
|
||||
}
|
||||
newRewrites := make([]*rewriteType, 0, len(rules))
|
||||
for _, r := range rules {
|
||||
s := &rewriteType{fromPath: r.Path, toPath: r.ToPath}
|
||||
if strings.ContainsRune(r.Path, '(') {
|
||||
matcher, err := regexp.Compile("^" + r.Path + "$")
|
||||
if err == nil {
|
||||
s.matcher = matcher
|
||||
}
|
||||
}
|
||||
newRewrites = append(newRewrites, s)
|
||||
newRewrites = append(newRewrites, parseRewriteRule(r.Path, r.ToPath))
|
||||
}
|
||||
fileRewrites[host] = newRewrites
|
||||
rebuildRewritesUnderLock(host)
|
||||
|
||||
48
proxy.go
48
proxy.go
@ -17,16 +17,32 @@ type proxyType struct {
|
||||
fromPath string
|
||||
toApp string
|
||||
toPath string
|
||||
hasWildcard bool
|
||||
prefix string
|
||||
toPrefix string
|
||||
}
|
||||
|
||||
func (hc *HostContext) Proxy(authLevel int, path string, toApp, toPath string) *HostContext {
|
||||
func parseProxyRule(authLevel int, path, toApp, toPath string) *proxyType {
|
||||
p := &proxyType{authLevel: authLevel, fromPath: path, toApp: toApp, toPath: toPath}
|
||||
if strings.Contains(path, "(") {
|
||||
if strings.ContainsRune(path, '(') {
|
||||
matcher, err := regexp.Compile("^" + path + "$")
|
||||
if err == nil {
|
||||
p.matcher = matcher
|
||||
}
|
||||
} else if strings.HasSuffix(path, "/*") {
|
||||
p.hasWildcard = true
|
||||
p.prefix = path[:len(path)-1]
|
||||
if strings.HasSuffix(toPath, "/*") {
|
||||
p.toPrefix = toPath[:len(toPath)-1]
|
||||
} else {
|
||||
p.toPrefix = toPath
|
||||
}
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
func (hc *HostContext) Proxy(authLevel int, path string, toApp, toPath string) *HostContext {
|
||||
p := parseProxyRule(authLevel, path, toApp, toPath)
|
||||
|
||||
hostPoliciesLock.Lock()
|
||||
defer hostPoliciesLock.Unlock()
|
||||
@ -71,12 +87,7 @@ func findProxy(request *Request) (int, *string, *string, string) {
|
||||
}
|
||||
|
||||
for _, pi := range proxies {
|
||||
if pi.matcher == nil {
|
||||
if pi.fromPath == requestPath {
|
||||
toPath := pi.toPath + queryString
|
||||
return pi.authLevel, &pi.toApp, &toPath, h
|
||||
}
|
||||
} else {
|
||||
if pi.matcher != nil {
|
||||
finds := pi.matcher.FindAllStringSubmatch(requestPath, 1)
|
||||
if len(finds) > 0 {
|
||||
toApp := pi.toApp
|
||||
@ -88,6 +99,18 @@ func findProxy(request *Request) (int, *string, *string, string) {
|
||||
toPath += queryString
|
||||
return pi.authLevel, &toApp, &toPath, h
|
||||
}
|
||||
} else if pi.hasWildcard {
|
||||
if strings.HasPrefix(requestPath, pi.prefix) {
|
||||
suffix := requestPath[len(pi.prefix):]
|
||||
toPath := pi.toPrefix + suffix + queryString
|
||||
toApp := pi.toApp
|
||||
return pi.authLevel, &toApp, &toPath, h
|
||||
}
|
||||
} else {
|
||||
if pi.fromPath == requestPath {
|
||||
toPath := pi.toPath + queryString
|
||||
return pi.authLevel, &pi.toApp, &toPath, h
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -184,14 +207,7 @@ type ProxyRule struct {
|
||||
func ReplaceProxies(host string, rules []ProxyRule) {
|
||||
newProxies := make([]*proxyType, 0, len(rules))
|
||||
for _, r := range rules {
|
||||
p := &proxyType{authLevel: r.AuthLevel, fromPath: r.Path, toApp: r.ToApp, toPath: r.ToPath}
|
||||
if strings.ContainsRune(r.Path, '(') {
|
||||
matcher, err := regexp.Compile("^" + r.Path + "$")
|
||||
if err == nil {
|
||||
p.matcher = matcher
|
||||
}
|
||||
}
|
||||
newProxies = append(newProxies, p)
|
||||
newProxies = append(newProxies, parseProxyRule(r.AuthLevel, r.Path, r.ToApp, r.ToPath))
|
||||
}
|
||||
|
||||
hostPoliciesLock.Lock()
|
||||
|
||||
52
rewrite.go
52
rewrite.go
@ -12,17 +12,32 @@ type rewriteType struct {
|
||||
matcher *regexp.Regexp
|
||||
fromPath string
|
||||
toPath string
|
||||
hasWildcard bool
|
||||
prefix string
|
||||
toPrefix string
|
||||
}
|
||||
|
||||
func (hc *HostContext) Rewrite(path string, toPath string) *HostContext {
|
||||
s := &rewriteType{fromPath: path, toPath: toPath}
|
||||
|
||||
if strings.ContainsRune(path, '(') {
|
||||
matcher, err := regexp.Compile("^" + path + "$")
|
||||
func parseRewriteRule(fromPath, toPath string) *rewriteType {
|
||||
s := &rewriteType{fromPath: fromPath, toPath: toPath}
|
||||
if strings.ContainsRune(fromPath, '(') {
|
||||
matcher, err := regexp.Compile("^" + fromPath + "$")
|
||||
if err == nil {
|
||||
s.matcher = matcher
|
||||
}
|
||||
} else if strings.HasSuffix(fromPath, "/*") {
|
||||
s.hasWildcard = true
|
||||
s.prefix = fromPath[:len(fromPath)-1]
|
||||
if strings.HasSuffix(toPath, "/*") {
|
||||
s.toPrefix = toPath[:len(toPath)-1]
|
||||
} else {
|
||||
s.toPrefix = toPath
|
||||
}
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func (hc *HostContext) Rewrite(path string, toPath string) *HostContext {
|
||||
s := parseRewriteRule(path, toPath)
|
||||
|
||||
hostPoliciesLock.Lock()
|
||||
defer hostPoliciesLock.Unlock()
|
||||
@ -68,12 +83,7 @@ func processRewrite(request *Request, response *Response, logger *log.Logger) bo
|
||||
found := false
|
||||
rewriteToPath := ""
|
||||
|
||||
if ri.matcher == nil {
|
||||
if ri.fromPath == requestPath {
|
||||
rewriteToPath = ri.toPath
|
||||
found = true
|
||||
}
|
||||
} else {
|
||||
if ri.matcher != nil {
|
||||
finds := ri.matcher.FindAllStringSubmatch(request.RequestURI, 1)
|
||||
if len(finds) > 0 {
|
||||
toPath := ri.toPath
|
||||
@ -83,6 +93,17 @@ func processRewrite(request *Request, response *Response, logger *log.Logger) bo
|
||||
rewriteToPath = toPath
|
||||
found = true
|
||||
}
|
||||
} else if ri.hasWildcard {
|
||||
if strings.HasPrefix(requestPath, ri.prefix) {
|
||||
suffix := requestPath[len(ri.prefix):]
|
||||
rewriteToPath = ri.toPrefix + suffix
|
||||
found = true
|
||||
}
|
||||
} else {
|
||||
if ri.fromPath == requestPath {
|
||||
rewriteToPath = ri.toPath
|
||||
found = true
|
||||
}
|
||||
}
|
||||
|
||||
if found {
|
||||
@ -121,14 +142,7 @@ type RewriteRule struct {
|
||||
func ReplaceRewrites(host string, rules []RewriteRule) {
|
||||
newRewrites := make([]*rewriteType, 0, len(rules))
|
||||
for _, r := range rules {
|
||||
s := &rewriteType{fromPath: r.Path, toPath: r.ToPath}
|
||||
if strings.ContainsRune(r.Path, '(') {
|
||||
matcher, err := regexp.Compile("^" + r.Path + "$")
|
||||
if err == nil {
|
||||
s.matcher = matcher
|
||||
}
|
||||
}
|
||||
newRewrites = append(newRewrites, s)
|
||||
newRewrites = append(newRewrites, parseRewriteRule(r.Path, r.ToPath))
|
||||
}
|
||||
|
||||
hostPoliciesLock.Lock()
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user