From d985a53fa66d1c94f52c67e4e78e51ba3ce79058 Mon Sep 17 00:00:00 2001 From: GoEdgeLab Date: Wed, 26 Oct 2022 16:14:37 +0800 Subject: [PATCH] =?UTF-8?q?URL=E8=B7=B3=E8=BD=AC=E4=B8=AD=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E5=9F=9F=E5=90=8D=E8=B7=B3=E8=BD=AC=E3=80=81=E7=AB=AF?= =?UTF-8?q?=E5=8F=A3=E8=B7=B3=E8=BD=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- internal/nodes/http_request_host_redirect.go | 222 +++++++++++++------ 1 file changed, 150 insertions(+), 72 deletions(-) diff --git a/internal/nodes/http_request_host_redirect.go b/internal/nodes/http_request_host_redirect.go index 781d264..7e11ad3 100644 --- a/internal/nodes/http_request_host_redirect.go +++ b/internal/nodes/http_request_host_redirect.go @@ -1,7 +1,11 @@ package nodes import ( + "github.com/TeaOSLab/EdgeCommon/pkg/configutils" + "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs" "github.com/TeaOSLab/EdgeNode/internal/utils" + "github.com/iwind/TeaGo/types" + "net" "net/http" "strconv" "strings" @@ -13,7 +17,7 @@ func (this *HTTPRequest) doHostRedirect() (blocked bool) { if this.web.MergeSlashes { urlPath = utils.CleanPath(urlPath) } - fullURL := this.requestScheme() + "://" + this.ReqHost + urlPath + var fullURL = this.requestScheme() + "://" + this.ReqHost + urlPath for _, u := range this.web.HostRedirects { if !u.IsOn { continue @@ -21,11 +25,50 @@ func (this *HTTPRequest) doHostRedirect() (blocked bool) { if !u.MatchRequest(this.Format) { continue } - if u.MatchPrefix { // 匹配前缀 - if strings.HasPrefix(fullURL, u.BeforeURL) { - afterURL := u.AfterURL - if u.KeepRequestURI { - afterURL += this.RawReq.URL.RequestURI() + if len(u.Type) == 0 || u.Type == serverconfigs.HTTPHostRedirectTypeURL { + if u.MatchPrefix { // 匹配前缀 + if strings.HasPrefix(fullURL, u.BeforeURL) { + afterURL := u.AfterURL + if u.KeepRequestURI { + afterURL += this.RawReq.URL.RequestURI() + } + + // 前后是否一致 + if fullURL == afterURL { + return false + } + + if u.Status <= 0 { + u.Status = http.StatusTemporaryRedirect + } + this.processResponseHeaders(this.writer.Header(), u.Status) + http.Redirect(this.RawWriter, this.RawReq, afterURL, u.Status) + return true + } + } else if u.MatchRegexp { // 正则匹配 + var reg = u.BeforeURLRegexp() + if reg == nil { + continue + } + var matches = reg.FindStringSubmatch(fullURL) + if len(matches) == 0 { + continue + } + var afterURL = u.AfterURL + for i, match := range matches { + afterURL = strings.ReplaceAll(afterURL, "${"+strconv.Itoa(i)+"}", match) + } + + var subNames = reg.SubexpNames() + if len(subNames) > 0 { + for _, subName := range subNames { + if len(subName) > 0 { + index := reg.SubexpIndex(subName) + if index > -1 { + afterURL = strings.ReplaceAll(afterURL, "${"+subName+"}", matches[index]) + } + } + } } // 前后是否一致 @@ -33,69 +76,6 @@ func (this *HTTPRequest) doHostRedirect() (blocked bool) { return false } - if u.Status <= 0 { - this.processResponseHeaders(this.writer.Header(), http.StatusTemporaryRedirect) - http.Redirect(this.RawWriter, this.RawReq, afterURL, http.StatusTemporaryRedirect) - } else { - this.processResponseHeaders(this.writer.Header(), u.Status) - http.Redirect(this.RawWriter, this.RawReq, afterURL, u.Status) - } - return true - } - } else if u.MatchRegexp { // 正则匹配 - reg := u.BeforeURLRegexp() - if reg == nil { - continue - } - matches := reg.FindStringSubmatch(fullURL) - if len(matches) == 0 { - continue - } - afterURL := u.AfterURL - for i, match := range matches { - afterURL = strings.ReplaceAll(afterURL, "${"+strconv.Itoa(i)+"}", match) - } - - subNames := reg.SubexpNames() - if len(subNames) > 0 { - for _, subName := range subNames { - if len(subName) > 0 { - index := reg.SubexpIndex(subName) - if index > -1 { - afterURL = strings.ReplaceAll(afterURL, "${"+subName+"}", matches[index]) - } - } - } - } - - // 前后是否一致 - if fullURL == afterURL { - return false - } - - if u.KeepArgs { - var qIndex = strings.Index(this.uri, "?") - if qIndex >= 0 { - afterURL += this.uri[qIndex:] - } - } - - if u.Status <= 0 { - this.processResponseHeaders(this.writer.Header(), http.StatusTemporaryRedirect) - http.Redirect(this.RawWriter, this.RawReq, afterURL, http.StatusTemporaryRedirect) - } else { - this.processResponseHeaders(this.writer.Header(), u.Status) - http.Redirect(this.RawWriter, this.RawReq, afterURL, u.Status) - } - return true - } else { // 精准匹配 - if fullURL == u.RealBeforeURL() { - // 前后是否一致 - if fullURL == u.AfterURL { - return false - } - - var afterURL = u.AfterURL if u.KeepArgs { var qIndex = strings.Index(this.uri, "?") if qIndex >= 0 { @@ -104,12 +84,110 @@ func (this *HTTPRequest) doHostRedirect() (blocked bool) { } if u.Status <= 0 { - this.processResponseHeaders(this.writer.Header(), http.StatusTemporaryRedirect) - http.Redirect(this.RawWriter, this.RawReq, afterURL, http.StatusTemporaryRedirect) - } else { + u.Status = http.StatusTemporaryRedirect + } + this.processResponseHeaders(this.writer.Header(), u.Status) + http.Redirect(this.RawWriter, this.RawReq, afterURL, u.Status) + return true + } else { // 精准匹配 + if fullURL == u.RealBeforeURL() { + // 前后是否一致 + if fullURL == u.AfterURL { + return false + } + + var afterURL = u.AfterURL + if u.KeepArgs { + var qIndex = strings.Index(this.uri, "?") + if qIndex >= 0 { + afterURL += this.uri[qIndex:] + } + } + + if u.Status <= 0 { + u.Status = http.StatusTemporaryRedirect + } this.processResponseHeaders(this.writer.Header(), u.Status) http.Redirect(this.RawWriter, this.RawReq, afterURL, u.Status) + return true } + } + } else if u.Type == serverconfigs.HTTPHostRedirectTypeDomain { + if len(u.DomainAfter) == 0 { + continue + } + + // 如果跳转前后域名一致,则终止 + if u.DomainAfter == this.ReqHost { + return false + } + + var scheme = u.DomainAfterScheme + if len(scheme) == 0 { + scheme = this.requestScheme() + } + if u.DomainsAll || configutils.MatchDomains(u.DomainsBefore, this.ReqHost) { + var afterURL = scheme + "://" + u.DomainAfter + urlPath + if fullURL == afterURL { + // 终止匹配 + return false + } + if u.Status <= 0 { + u.Status = http.StatusTemporaryRedirect + } + this.processResponseHeaders(this.writer.Header(), u.Status) + http.Redirect(this.RawWriter, this.RawReq, afterURL, u.Status) + return true + } + } else if u.Type == serverconfigs.HTTPHostRedirectTypePort { + if u.PortAfter <= 0 { + continue + } + + var scheme = u.PortAfterScheme + if len(scheme) == 0 { + scheme = this.requestScheme() + } + + reqHost, reqPort, _ := net.SplitHostPort(this.ReqHost) + if len(reqHost) == 0 { + reqHost = this.ReqHost + } + if len(reqPort) == 0 { + switch this.requestScheme() { + case "http": + reqPort = "80" + case "https": + reqPort = "443" + } + } + + // 如果跳转前后端口一致,则终止 + if reqPort == types.String(u.PortAfter) { + return false + } + + var containsPort = false + if u.PortsAll { + containsPort = true + } else { + containsPort = u.ContainsPort(types.Int(reqPort)) + } + if containsPort { + var newReqHost = reqHost + if !((scheme == "http" && u.PortAfter == 80) || (scheme == "https" && u.PortAfter == 443)) { + newReqHost += ":" + types.String(u.PortAfter) + } + var afterURL = scheme + "://" + newReqHost + urlPath + if fullURL == afterURL { + // 终止匹配 + return false + } + if u.Status <= 0 { + u.Status = http.StatusTemporaryRedirect + } + this.processResponseHeaders(this.writer.Header(), u.Status) + http.Redirect(this.RawWriter, this.RawReq, afterURL, u.Status) return true } }