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  }