github.com/TeaOSLab/EdgeNode@v1.3.8/internal/nodes/http_request_host_redirect.go (about) 1 package nodes 2 3 import ( 4 "github.com/TeaOSLab/EdgeCommon/pkg/configutils" 5 "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs" 6 "github.com/TeaOSLab/EdgeNode/internal/utils" 7 "github.com/iwind/TeaGo/types" 8 "net" 9 "net/http" 10 "strconv" 11 "strings" 12 ) 13 14 // 主机地址快速跳转 15 func (this *HTTPRequest) doHostRedirect() (blocked bool) { 16 var urlPath = this.RawReq.URL.Path 17 if this.web.MergeSlashes { 18 urlPath = utils.CleanPath(urlPath) 19 } 20 for _, u := range this.web.HostRedirects { 21 if !u.IsOn { 22 continue 23 } 24 if !u.MatchRequest(this.Format) { 25 continue 26 } 27 28 if len(u.ExceptDomains) > 0 && configutils.MatchDomains(u.ExceptDomains, this.ReqHost) { 29 continue 30 } 31 if len(u.OnlyDomains) > 0 && !configutils.MatchDomains(u.OnlyDomains, this.ReqHost) { 32 continue 33 } 34 35 var status = u.Status 36 if status <= 0 { 37 if searchEngineRegex.MatchString(this.RawReq.UserAgent()) { 38 status = http.StatusMovedPermanently 39 } else { 40 status = http.StatusTemporaryRedirect 41 } 42 } 43 44 var fullURL string 45 if u.BeforeHasQuery() { 46 fullURL = this.URL() 47 } else { 48 fullURL = this.requestScheme() + "://" + this.ReqHost + urlPath 49 } 50 51 if len(u.Type) == 0 || u.Type == serverconfigs.HTTPHostRedirectTypeURL { 52 if u.MatchPrefix { // 匹配前缀 53 if strings.HasPrefix(fullURL, u.BeforeURL) { 54 var afterURL = u.AfterURL 55 if u.KeepRequestURI { 56 afterURL += this.RawReq.URL.RequestURI() 57 } 58 59 // 前后是否一致 60 if fullURL == afterURL { 61 return false 62 } 63 64 this.ProcessResponseHeaders(this.writer.Header(), status) 65 httpRedirect(this.writer, this.RawReq, afterURL, status) 66 return true 67 } 68 } else if u.MatchRegexp { // 正则匹配 69 var reg = u.BeforeURLRegexp() 70 if reg == nil { 71 continue 72 } 73 var matches = reg.FindStringSubmatch(fullURL) 74 if len(matches) == 0 { 75 continue 76 } 77 var afterURL = u.AfterURL 78 for i, match := range matches { 79 afterURL = strings.ReplaceAll(afterURL, "${"+strconv.Itoa(i)+"}", match) 80 } 81 82 var subNames = reg.SubexpNames() 83 if len(subNames) > 0 { 84 for _, subName := range subNames { 85 if len(subName) > 0 { 86 index := reg.SubexpIndex(subName) 87 if index > -1 { 88 afterURL = strings.ReplaceAll(afterURL, "${"+subName+"}", matches[index]) 89 } 90 } 91 } 92 } 93 94 // 前后是否一致 95 if fullURL == afterURL { 96 return false 97 } 98 99 if u.KeepArgs { 100 var qIndex = strings.Index(this.uri, "?") 101 if qIndex >= 0 { 102 afterURL += this.uri[qIndex:] 103 } 104 } 105 106 this.ProcessResponseHeaders(this.writer.Header(), status) 107 httpRedirect(this.writer, this.RawReq, afterURL, status) 108 return true 109 } else { // 精准匹配 110 if fullURL == u.RealBeforeURL() { 111 // 前后是否一致 112 if fullURL == u.AfterURL { 113 return false 114 } 115 116 var afterURL = u.AfterURL 117 if u.KeepArgs { 118 var qIndex = strings.Index(this.uri, "?") 119 if qIndex >= 0 { 120 var afterQIndex = strings.Index(u.AfterURL, "?") 121 if afterQIndex >= 0 { 122 afterURL = u.AfterURL[:afterQIndex] + this.uri[qIndex:] 123 } else { 124 afterURL += this.uri[qIndex:] 125 } 126 } 127 } 128 129 this.ProcessResponseHeaders(this.writer.Header(), status) 130 httpRedirect(this.writer, this.RawReq, afterURL, status) 131 return true 132 } 133 } 134 } else if u.Type == serverconfigs.HTTPHostRedirectTypeDomain { 135 if len(u.DomainAfter) == 0 { 136 continue 137 } 138 139 var reqHost = this.ReqHost 140 141 // 忽略跳转前端口 142 if u.DomainBeforeIgnorePorts { 143 h, _, err := net.SplitHostPort(reqHost) 144 if err == nil && len(h) > 0 { 145 reqHost = h 146 } 147 } 148 149 var scheme = u.DomainAfterScheme 150 if len(scheme) == 0 { 151 scheme = this.requestScheme() 152 } 153 if u.DomainsAll || configutils.MatchDomains(u.DomainsBefore, reqHost) { 154 var afterURL = scheme + "://" + u.DomainAfter + urlPath 155 if fullURL == afterURL { 156 // 终止匹配 157 return false 158 } 159 160 // 如果跳转前后域名一致,则终止 161 if u.DomainAfter == reqHost { 162 return false 163 } 164 165 this.ProcessResponseHeaders(this.writer.Header(), status) 166 167 // 参数 168 var qIndex = strings.Index(this.uri, "?") 169 if qIndex >= 0 { 170 afterURL += this.uri[qIndex:] 171 } 172 173 httpRedirect(this.writer, this.RawReq, afterURL, status) 174 return true 175 } 176 } else if u.Type == serverconfigs.HTTPHostRedirectTypePort { 177 if u.PortAfter <= 0 { 178 continue 179 } 180 181 var scheme = u.PortAfterScheme 182 if len(scheme) == 0 { 183 scheme = this.requestScheme() 184 } 185 186 reqHost, reqPort, _ := net.SplitHostPort(this.ReqHost) 187 if len(reqHost) == 0 { 188 reqHost = this.ReqHost 189 } 190 if len(reqPort) == 0 { 191 switch this.requestScheme() { 192 case "http": 193 reqPort = "80" 194 case "https": 195 reqPort = "443" 196 } 197 } 198 199 // 如果跳转前后端口一致,则终止 200 if reqPort == types.String(u.PortAfter) { 201 return false 202 } 203 204 var containsPort bool 205 if u.PortsAll { 206 containsPort = true 207 } else { 208 containsPort = u.ContainsPort(types.Int(reqPort)) 209 } 210 if containsPort { 211 var newReqHost = reqHost 212 if !((scheme == "http" && u.PortAfter == 80) || (scheme == "https" && u.PortAfter == 443)) { 213 newReqHost += ":" + types.String(u.PortAfter) 214 } 215 var afterURL = scheme + "://" + newReqHost + urlPath 216 if fullURL == afterURL { 217 // 终止匹配 218 return false 219 } 220 221 this.ProcessResponseHeaders(this.writer.Header(), status) 222 httpRedirect(this.writer, this.RawReq, afterURL, status) 223 return true 224 } 225 } 226 } 227 return 228 }