|
|
|
@@ -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]
|
|
|
|
|
}
|
|
|
|
@@ -110,13 +127,13 @@ func (router *Router) rewriteURL(rooturl string, requestURL string) string {
|
|
|
|
|
// upstreamHostSwap check if this loopback to one of the proxy rule in the system. If yes, do a shortcut target swap
|
|
|
|
|
// this prevents unnecessary external DNS lookup and connection, return true if swapped and request is already handled
|
|
|
|
|
// by the loopback handler. Only continue if return is false
|
|
|
|
|
func (h *ProxyHandler) upstreamHostSwap(w http.ResponseWriter, r *http.Request, selectedUpstream *loadbalance.Upstream) bool {
|
|
|
|
|
func (h *ProxyHandler) upstreamHostSwap(w http.ResponseWriter, r *http.Request, selectedUpstream *loadbalance.Upstream, currentTarget *ProxyEndpoint) bool {
|
|
|
|
|
upstreamHostname := selectedUpstream.OriginIpOrDomain
|
|
|
|
|
if strings.Contains(upstreamHostname, ":") {
|
|
|
|
|
upstreamHostname = strings.Split(upstreamHostname, ":")[0]
|
|
|
|
|
}
|
|
|
|
|
loopbackProxyEndpoint := h.Parent.GetProxyEndpointFromHostname(upstreamHostname)
|
|
|
|
|
if loopbackProxyEndpoint != nil {
|
|
|
|
|
if loopbackProxyEndpoint != nil && loopbackProxyEndpoint != currentTarget {
|
|
|
|
|
//This is a loopback request. Swap the target to the loopback target
|
|
|
|
|
//h.Parent.Option.Logger.PrintAndLog("proxy", "Detected a loopback request to self. Swap the target to "+loopbackProxyEndpoint.RootOrMatchingDomain, nil)
|
|
|
|
|
if loopbackProxyEndpoint.IsEnabled() {
|
|
|
|
@@ -147,7 +164,7 @@ func (h *ProxyHandler) hostRequest(w http.ResponseWriter, r *http.Request, targe
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Upstream Host Swap (use to detect loopback to self) */
|
|
|
|
|
if h.upstreamHostSwap(w, r, selectedUpstream) {
|
|
|
|
|
if h.upstreamHostSwap(w, r, selectedUpstream, target) {
|
|
|
|
|
//Request handled by the loopback handler
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|