github.com/TeaOSLab/EdgeNode@v1.3.8/internal/nodes/http_request.go (about)

     1  package nodes
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"errors"
     7  	"fmt"
     8  	"github.com/TeaOSLab/EdgeCommon/pkg/configutils"
     9  	iplib "github.com/TeaOSLab/EdgeCommon/pkg/iplibrary"
    10  	"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
    11  	"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
    12  	teaconst "github.com/TeaOSLab/EdgeNode/internal/const"
    13  	"github.com/TeaOSLab/EdgeNode/internal/metrics"
    14  	"github.com/TeaOSLab/EdgeNode/internal/stats"
    15  	"github.com/TeaOSLab/EdgeNode/internal/utils"
    16  	"github.com/iwind/TeaGo/lists"
    17  	"github.com/iwind/TeaGo/maps"
    18  	"github.com/iwind/TeaGo/types"
    19  	"io"
    20  	"net"
    21  	"net/http"
    22  	"net/url"
    23  	"os"
    24  	"path/filepath"
    25  	"strconv"
    26  	"strings"
    27  	"time"
    28  )
    29  
    30  // 环境变量
    31  var HOSTNAME, _ = os.Hostname()
    32  
    33  // errors
    34  var errWritingToClient = errors.New("writing to client error")
    35  
    36  // HTTPRequest HTTP请求
    37  type HTTPRequest struct {
    38  	requestId string
    39  
    40  	// 外部参数
    41  	RawReq        *http.Request
    42  	RawWriter     http.ResponseWriter
    43  	ReqServer     *serverconfigs.ServerConfig
    44  	ReqHost       string // 请求的Host
    45  	ServerName    string // 实际匹配到的Host
    46  	ServerAddr    string // 实际启动的服务器监听地址
    47  	IsHTTP        bool
    48  	IsHTTPS       bool
    49  	IsHTTP3       bool
    50  	isHealthCheck bool
    51  
    52  	// 共享参数
    53  	// DO NOT change the variable after created
    54  	nodeConfig *nodeconfigs.NodeConfig
    55  
    56  	// ln request
    57  	isLnRequest  bool
    58  	lnRemoteAddr string
    59  
    60  	// 内部参数
    61  	isSubRequest         bool
    62  	writer               *HTTPWriter
    63  	web                  *serverconfigs.HTTPWebConfig      // Web配置,重要提示:由于引用了别的共享的配置,所以操作中只能读取不要修改
    64  	reverseProxyRef      *serverconfigs.ReverseProxyRef    // 反向代理引用
    65  	reverseProxy         *serverconfigs.ReverseProxyConfig // 反向代理配置,重要提示:由于引用了别的共享的配置,所以操作中只能读取不要修改
    66  	rawURI               string                            // 原始的URI
    67  	uri                  string                            // 经过rewrite等运算之后的URI
    68  	varMapping           map[string]string                 // 变量集合
    69  	requestFromTime      time.Time                         // 请求开始时间
    70  	requestCost          float64                           // 请求耗时
    71  	filePath             string                            // 请求的文件名,仅在读取Root目录下的内容时不为空
    72  	origin               *serverconfigs.OriginConfig       // 源站
    73  	originAddr           string                            // 源站实际地址
    74  	originStatus         int32                             // 源站响应代码
    75  	errors               []string                          // 错误信息
    76  	rewriteRule          *serverconfigs.HTTPRewriteRule    // 匹配到的重写规则
    77  	rewriteReplace       string                            // 重写规则的目标
    78  	rewriteIsExternalURL bool                              // 重写目标是否为外部URL
    79  	remoteAddr           string                            // 计算后的RemoteAddr
    80  
    81  	cacheRef         *serverconfigs.HTTPCacheRef // 缓存设置
    82  	cacheKey         string                      // 缓存使用的Key
    83  	isCached         bool                        // 是否已经被缓存
    84  	cacheCanTryStale bool                        // 是否可以尝试使用Stale缓存
    85  
    86  	isAttack        bool   // 是否是攻击请求
    87  	requestBodyData []byte // 读取的Body内容
    88  
    89  	isWebsocketResponse bool // 是否为Websocket响应(非请求)
    90  
    91  	// WAF相关
    92  	firewallPolicyId    int64
    93  	firewallRuleGroupId int64
    94  	firewallRuleSetId   int64
    95  	firewallRuleId      int64
    96  	firewallActions     []string
    97  	wafHasRequestBody   bool
    98  
    99  	tags []string
   100  
   101  	logAttrs map[string]string
   102  
   103  	disableLog bool // 是否在当前请求中关闭Log
   104  	forceLog   bool // 是否强制记录日志
   105  
   106  	disableMetrics bool // 不记录统计指标
   107  
   108  	isHijacked bool
   109  
   110  	// script相关操作
   111  	isDone bool
   112  }
   113  
   114  // 初始化
   115  func (this *HTTPRequest) init() {
   116  	this.writer = NewHTTPWriter(this, this.RawWriter)
   117  	this.web = &serverconfigs.HTTPWebConfig{
   118  		IsOn: true,
   119  	}
   120  
   121  	// this.uri = this.RawReq.URL.RequestURI()
   122  	// 之所以不使用RequestURI(),是不想让URL中的Path被Encode
   123  	var urlPath = this.RawReq.URL.Path
   124  	if this.ReqServer.Web != nil && this.ReqServer.Web.MergeSlashes {
   125  		urlPath = utils.CleanPath(urlPath)
   126  		this.web.MergeSlashes = true
   127  	}
   128  	if len(this.RawReq.URL.RawQuery) > 0 {
   129  		this.uri = urlPath + "?" + this.RawReq.URL.RawQuery
   130  	} else {
   131  		this.uri = urlPath
   132  	}
   133  
   134  	this.rawURI = this.uri
   135  	this.varMapping = map[string]string{
   136  		// 缓存相关初始化
   137  		"cache.status":      "BYPASS",
   138  		"cache.age":         "0",
   139  		"cache.key":         "",
   140  		"cache.policy.name": "",
   141  		"cache.policy.id":   "0",
   142  		"cache.policy.type": "",
   143  	}
   144  	this.logAttrs = map[string]string{}
   145  	this.requestFromTime = time.Now()
   146  	this.requestId = httpRequestNextId()
   147  }
   148  
   149  // Do 执行请求
   150  func (this *HTTPRequest) Do() {
   151  	// 初始化
   152  	this.init()
   153  
   154  	// 当前服务的反向代理配置
   155  	if this.ReqServer.ReverseProxyRef != nil && this.ReqServer.ReverseProxy != nil {
   156  		this.reverseProxyRef = this.ReqServer.ReverseProxyRef
   157  		this.reverseProxy = this.ReqServer.ReverseProxy
   158  	}
   159  
   160  	// Web配置
   161  	err := this.configureWeb(this.ReqServer.Web, true, 0)
   162  	if err != nil {
   163  		this.write50x(err, http.StatusInternalServerError, "Failed to configure the server", "配置服务失败", false)
   164  		this.doEnd()
   165  		return
   166  	}
   167  
   168  	// 是否为低级别节点
   169  	this.isLnRequest = this.checkLnRequest()
   170  
   171  	// 回调事件
   172  	this.onInit()
   173  	if this.writer.isFinished {
   174  		this.doEnd()
   175  		return
   176  	}
   177  
   178  	// 处理健康检查
   179  	var healthCheckKey = this.RawReq.Header.Get(serverconfigs.HealthCheckHeaderName)
   180  	if len(healthCheckKey) > 0 {
   181  		if this.doHealthCheck(healthCheckKey, &this.isHealthCheck) {
   182  			this.doEnd()
   183  			return
   184  		}
   185  	}
   186  
   187  	if !this.isLnRequest {
   188  		// 特殊URL处理
   189  		if len(this.rawURI) > 1 && this.rawURI[1] == '.' {
   190  			// ACME
   191  			// TODO 需要配置是否启用ACME检测
   192  			if strings.HasPrefix(this.rawURI, "/.well-known/acme-challenge/") {
   193  				if this.doACME() {
   194  					this.doEnd()
   195  					return
   196  				}
   197  			}
   198  		}
   199  
   200  		// 套餐
   201  		if this.ReqServer.UserPlan != nil {
   202  			if this.doPlanBefore() {
   203  				this.doEnd()
   204  				return
   205  			}
   206  		}
   207  
   208  		// 流量限制
   209  		if this.ReqServer.TrafficLimitStatus != nil && this.ReqServer.TrafficLimitStatus.IsValid() {
   210  			if this.doTrafficLimit(this.ReqServer.TrafficLimitStatus) {
   211  				this.doEnd()
   212  				return
   213  			}
   214  		}
   215  
   216  		// UAM
   217  		var uamIsCalled = false
   218  		if !this.isHealthCheck {
   219  			if this.web.UAM == nil && this.ReqServer.UAM != nil && this.ReqServer.UAM.IsOn {
   220  				this.web.UAM = this.ReqServer.UAM
   221  			}
   222  
   223  			if this.web.UAM != nil && this.web.UAM.IsOn && this.isUAMRequest() {
   224  				uamIsCalled = true
   225  				if this.doUAM() {
   226  					this.doEnd()
   227  					return
   228  				}
   229  			}
   230  		}
   231  
   232  		// WAF
   233  		if this.web.FirewallRef != nil && this.web.FirewallRef.IsOn {
   234  			if this.doWAFRequest() {
   235  				this.doEnd()
   236  				return
   237  			}
   238  		}
   239  
   240  		// UAM
   241  		if !this.isHealthCheck && !uamIsCalled {
   242  			if this.web.UAM != nil && this.web.UAM.IsOn {
   243  				if this.doUAM() {
   244  					this.doEnd()
   245  					return
   246  				}
   247  			}
   248  		}
   249  
   250  		// CC
   251  		if !this.isHealthCheck {
   252  			if this.web.CC != nil {
   253  				if this.web.CC.IsOn {
   254  					if this.doCC() {
   255  						this.doEnd()
   256  						return
   257  					}
   258  				}
   259  			}
   260  		}
   261  
   262  		// 防盗链
   263  		if !this.isSubRequest && this.web.Referers != nil && this.web.Referers.IsOn {
   264  			if this.doCheckReferers() {
   265  				this.doEnd()
   266  				return
   267  			}
   268  		}
   269  
   270  		// UA名单
   271  		if !this.isSubRequest && this.web.UserAgent != nil && this.web.UserAgent.IsOn {
   272  			if this.doCheckUserAgent() {
   273  				this.doEnd()
   274  				return
   275  			}
   276  		}
   277  
   278  		// 访问控制
   279  		if !this.isSubRequest && this.web.Auth != nil && this.web.Auth.IsOn {
   280  			if this.doAuth() {
   281  				this.doEnd()
   282  				return
   283  			}
   284  		}
   285  
   286  		// 自动跳转到HTTPS
   287  		if this.IsHTTP && this.web.RedirectToHttps != nil && this.web.RedirectToHttps.IsOn {
   288  			if this.doRedirectToHTTPS(this.web.RedirectToHttps) {
   289  				this.doEnd()
   290  				return
   291  			}
   292  		}
   293  
   294  		// Compression
   295  		if this.web.Compression != nil && this.web.Compression.IsOn && this.web.Compression.Level > 0 {
   296  			this.writer.SetCompression(this.web.Compression)
   297  		}
   298  
   299  		// HLS
   300  		if this.web.HLS != nil &&
   301  			this.web.HLS.Encrypting != nil &&
   302  			this.web.HLS.Encrypting.IsOn {
   303  			if this.processHLSBefore() {
   304  				this.doEnd()
   305  				return
   306  			}
   307  		}
   308  	}
   309  
   310  	// 开始调用
   311  	this.doBegin()
   312  
   313  	// 关闭写入
   314  	this.writer.Close()
   315  
   316  	// 结束调用
   317  	this.doEnd()
   318  }
   319  
   320  // 开始调用
   321  func (this *HTTPRequest) doBegin() {
   322  	// 是否找不到域名匹配
   323  	if this.ReqServer.Id == 0 {
   324  		this.doMismatch()
   325  		return
   326  	}
   327  
   328  	if !this.isLnRequest {
   329  		// 处理request limit
   330  		if this.web.RequestLimit != nil &&
   331  			this.web.RequestLimit.IsOn {
   332  			if this.doRequestLimit() {
   333  				return
   334  			}
   335  		}
   336  
   337  		// 处理requestBody
   338  		if this.RawReq.ContentLength > 0 &&
   339  			this.web.AccessLogRef != nil &&
   340  			this.web.AccessLogRef.IsOn &&
   341  			this.web.AccessLogRef.ContainsField(serverconfigs.HTTPAccessLogFieldRequestBody) {
   342  			var err error
   343  			this.requestBodyData, err = io.ReadAll(io.LimitReader(this.RawReq.Body, AccessLogMaxRequestBodySize))
   344  			if err != nil {
   345  				this.write50x(err, http.StatusBadGateway, "Failed to read request body for access log", "为访问日志读取请求Body失败", false)
   346  				return
   347  			}
   348  			this.RawReq.Body = io.NopCloser(io.MultiReader(bytes.NewBuffer(this.requestBodyData), this.RawReq.Body))
   349  		}
   350  
   351  		// 跳转
   352  		if len(this.web.HostRedirects) > 0 {
   353  			if this.doHostRedirect() {
   354  				return
   355  			}
   356  		}
   357  
   358  		// 临时关闭页面
   359  		if this.web.Shutdown != nil && this.web.Shutdown.IsOn {
   360  			this.doShutdown()
   361  			return
   362  		}
   363  	}
   364  
   365  	// 缓存
   366  	if this.web.Cache != nil && this.web.Cache.IsOn {
   367  		if this.doCacheRead(false) {
   368  			return
   369  		}
   370  	}
   371  
   372  	if !this.isLnRequest {
   373  		// 重写规则
   374  		if this.rewriteRule != nil {
   375  			if this.doRewrite() {
   376  				return
   377  			}
   378  		}
   379  
   380  		// Fastcgi
   381  		if this.web.FastcgiRef != nil && this.web.FastcgiRef.IsOn && len(this.web.FastcgiList) > 0 {
   382  			if this.doFastcgi() {
   383  				return
   384  			}
   385  		}
   386  
   387  		// root
   388  		if this.web.Root != nil && this.web.Root.IsOn {
   389  			// 如果处理成功,则终止请求的处理
   390  			if this.doRoot() {
   391  				return
   392  			}
   393  
   394  			// 如果明确设置了终止,则也会自动终止
   395  			if this.web.Root.IsBreak {
   396  				return
   397  			}
   398  		}
   399  	}
   400  
   401  	// Reverse Proxy
   402  	if this.reverseProxyRef != nil && this.reverseProxyRef.IsOn && this.reverseProxy != nil && this.reverseProxy.IsOn {
   403  		this.doReverseProxy()
   404  		return
   405  	}
   406  
   407  	// 返回404页面
   408  	this.write404()
   409  }
   410  
   411  // 结束调用
   412  func (this *HTTPRequest) doEnd() {
   413  	// 记录日志
   414  	this.log()
   415  
   416  	// 流量统计
   417  	// TODO 增加是否开启开关
   418  	if this.ReqServer != nil && this.ReqServer.Id > 0 && !this.isHealthCheck /** 健康检查时不统计 **/ {
   419  		var totalBytes int64 = 0
   420  
   421  		var requestConn = this.RawReq.Context().Value(HTTPConnContextKey)
   422  		if requestConn != nil {
   423  			requestClientConn, ok := requestConn.(ClientConnInterface)
   424  			if ok {
   425  				// 这里读取的其实是上一个请求消耗的流量,不是当前请求消耗的流量,只不过单个请求的流量统计不需要特别精确,整体趋于一致即可
   426  				totalBytes = requestClientConn.LastRequestBytes()
   427  			}
   428  		}
   429  
   430  		if totalBytes == 0 {
   431  			totalBytes = this.writer.SentBodyBytes() + this.writer.SentHeaderBytes()
   432  		}
   433  
   434  		var countCached int64 = 0
   435  		var cachedBytes int64 = 0
   436  
   437  		var countAttacks int64 = 0
   438  		var attackBytes int64 = 0
   439  
   440  		var countWebsocketConnections int64 = 0
   441  
   442  		if this.isCached {
   443  			countCached = 1
   444  			cachedBytes = totalBytes
   445  		}
   446  		if this.isAttack {
   447  			countAttacks = 1
   448  			attackBytes = this.CalculateSize()
   449  			if attackBytes < totalBytes {
   450  				attackBytes = totalBytes
   451  			}
   452  		}
   453  		if this.isWebsocketResponse {
   454  			countWebsocketConnections = 1
   455  		}
   456  
   457  		stats.SharedTrafficStatManager.Add(this.ReqServer.UserId, this.ReqServer.Id, this.ReqHost, totalBytes, cachedBytes, 1, countCached, countAttacks, attackBytes, countWebsocketConnections, this.ReqServer.ShouldCheckTrafficLimit(), this.ReqServer.PlanId())
   458  
   459  		// unique IP
   460  		stats.SharedDAUManager.AddIP(this.ReqServer.Id, this.requestRemoteAddr(true))
   461  
   462  		// 指标
   463  		if !this.disableMetrics && metrics.SharedManager.HasHTTPMetrics() {
   464  			this.doMetricsResponse()
   465  		}
   466  
   467  		// 统计
   468  		if this.web.StatRef != nil && this.web.StatRef.IsOn {
   469  			// 放到最后执行
   470  			this.doStat()
   471  		}
   472  	}
   473  }
   474  
   475  // RawURI 原始的请求URI
   476  func (this *HTTPRequest) RawURI() string {
   477  	return this.rawURI
   478  }
   479  
   480  // 配置
   481  func (this *HTTPRequest) configureWeb(web *serverconfigs.HTTPWebConfig, isTop bool, redirects int) error {
   482  	if web == nil || !web.IsOn {
   483  		return nil
   484  	}
   485  
   486  	// 防止跳转次数过多
   487  	if redirects > 8 {
   488  		return errors.New("too many redirects")
   489  	}
   490  	redirects++
   491  
   492  	// uri
   493  	rawPath := ""
   494  	rawQuery := ""
   495  	qIndex := strings.Index(this.uri, "?") // question mark index
   496  	if qIndex > -1 {
   497  		rawPath = this.uri[:qIndex]
   498  		rawQuery = this.uri[qIndex+1:]
   499  	} else {
   500  		rawPath = this.uri
   501  	}
   502  
   503  	// redirect
   504  	if web.RedirectToHttps != nil && (web.RedirectToHttps.IsPrior || isTop) {
   505  		this.web.RedirectToHttps = web.RedirectToHttps
   506  	}
   507  
   508  	// pages
   509  	if len(web.Pages) > 0 {
   510  		this.web.Pages = web.Pages
   511  	}
   512  
   513  	// shutdown
   514  	if web.Shutdown != nil && (web.Shutdown.IsPrior || isTop) {
   515  		this.web.Shutdown = web.Shutdown
   516  	}
   517  
   518  	// headers
   519  	if web.RequestHeaderPolicyRef != nil && (web.RequestHeaderPolicyRef.IsPrior || isTop) && web.RequestHeaderPolicy != nil {
   520  		// TODO 现在是只能选一个有效的设置,未来可以选择是否合并多级别的设置
   521  		this.web.RequestHeaderPolicy = web.RequestHeaderPolicy
   522  	}
   523  	if web.ResponseHeaderPolicyRef != nil && (web.ResponseHeaderPolicyRef.IsPrior || isTop) && web.ResponseHeaderPolicy != nil {
   524  		// TODO 现在是只能选一个有效的设置,未来可以选择是否合并多级别的设置
   525  		this.web.ResponseHeaderPolicy = web.ResponseHeaderPolicy
   526  	}
   527  
   528  	// root
   529  	if web.Root != nil && (web.Root.IsPrior || isTop) {
   530  		this.web.Root = web.Root
   531  	}
   532  
   533  	// remote addr
   534  	if web.RemoteAddr != nil && (web.RemoteAddr.IsPrior || isTop) && web.RemoteAddr.IsOn {
   535  		this.web.RemoteAddr = web.RemoteAddr
   536  
   537  		// check if from proxy
   538  		if len(this.web.RemoteAddr.Value) > 0 && this.web.RemoteAddr.Value != "${rawRemoteAddr}" {
   539  			var requestConn = this.RawReq.Context().Value(HTTPConnContextKey)
   540  			if requestConn != nil {
   541  				requestClientConn, ok := requestConn.(ClientConnInterface)
   542  				if ok {
   543  					requestClientConn.SetIsPersistent(true)
   544  				}
   545  			}
   546  		}
   547  	}
   548  
   549  	// charset
   550  	if web.Charset != nil && (web.Charset.IsPrior || isTop) {
   551  		this.web.Charset = web.Charset
   552  	}
   553  
   554  	// websocket
   555  	if web.WebsocketRef != nil && (web.WebsocketRef.IsPrior || isTop) {
   556  		this.web.WebsocketRef = web.WebsocketRef
   557  		this.web.Websocket = web.Websocket
   558  	}
   559  
   560  	// compression
   561  	if web.Compression != nil && (web.Compression.IsPrior || isTop) {
   562  		this.web.Compression = web.Compression
   563  	}
   564  
   565  	// optimizer
   566  	if web.Optimization != nil && (web.Optimization.IsPrior || (isTop && web.Optimization.IsOn())) {
   567  		this.web.Optimization = web.Optimization
   568  	}
   569  
   570  	// webp
   571  	if web.WebP != nil && (web.WebP.IsPrior || isTop) {
   572  		this.web.WebP = web.WebP
   573  	}
   574  
   575  	// cache
   576  	if web.Cache != nil && (web.Cache.IsPrior || isTop) {
   577  		this.web.Cache = web.Cache
   578  	}
   579  
   580  	// waf
   581  	if web.FirewallRef != nil && (web.FirewallRef.IsPrior || isTop) {
   582  		this.web.FirewallRef = web.FirewallRef
   583  		if web.FirewallPolicy != nil {
   584  			this.web.FirewallPolicy = web.FirewallPolicy
   585  		}
   586  	}
   587  
   588  	// access log
   589  	if web.AccessLogRef != nil && (web.AccessLogRef.IsPrior || isTop) {
   590  		this.web.AccessLogRef = web.AccessLogRef
   591  	}
   592  
   593  	// host redirects
   594  	if len(web.HostRedirects) > 0 {
   595  		this.web.HostRedirects = web.HostRedirects
   596  	}
   597  
   598  	// stat
   599  	if web.StatRef != nil && (web.StatRef.IsPrior || isTop) {
   600  		this.web.StatRef = web.StatRef
   601  	}
   602  
   603  	// fastcgi
   604  	if web.FastcgiRef != nil && (web.FastcgiRef.IsPrior || isTop) {
   605  		this.web.FastcgiRef = web.FastcgiRef
   606  		this.web.FastcgiList = web.FastcgiList
   607  	}
   608  
   609  	// auth
   610  	if web.Auth != nil && (web.Auth.IsPrior || isTop) {
   611  		this.web.Auth = web.Auth
   612  	}
   613  
   614  	// referers
   615  	if web.Referers != nil && (web.Referers.IsPrior || isTop) {
   616  		this.web.Referers = web.Referers
   617  	}
   618  
   619  	// user agent
   620  	if web.UserAgent != nil && (web.UserAgent.IsPrior || isTop) {
   621  		this.web.UserAgent = web.UserAgent
   622  	}
   623  
   624  	// request limit
   625  	if web.RequestLimit != nil && (web.RequestLimit.IsPrior || isTop) {
   626  		this.web.RequestLimit = web.RequestLimit
   627  	}
   628  
   629  	// request scripts
   630  	if web.RequestScripts != nil {
   631  		if this.web.RequestScripts == nil {
   632  			this.web.RequestScripts = &serverconfigs.HTTPRequestScriptsConfig{
   633  				InitGroup:    web.RequestScripts.InitGroup,
   634  				RequestGroup: web.RequestScripts.RequestGroup,
   635  			} // 不要直接赋值,需要复制,防止在运行时被修改
   636  		} else {
   637  			if web.RequestScripts.InitGroup != nil && (web.RequestScripts.InitGroup.IsPrior || isTop) {
   638  				if this.web.RequestScripts == nil {
   639  					this.web.RequestScripts = &serverconfigs.HTTPRequestScriptsConfig{}
   640  				}
   641  				this.web.RequestScripts.InitGroup = web.RequestScripts.InitGroup
   642  			}
   643  			if web.RequestScripts.RequestGroup != nil && (web.RequestScripts.RequestGroup.IsPrior || isTop) {
   644  				if this.web.RequestScripts == nil {
   645  					this.web.RequestScripts = &serverconfigs.HTTPRequestScriptsConfig{}
   646  				}
   647  				this.web.RequestScripts.RequestGroup = web.RequestScripts.RequestGroup
   648  			}
   649  		}
   650  	}
   651  
   652  	// UAM
   653  	if web.UAM != nil && (web.UAM.IsPrior || isTop) {
   654  		this.web.UAM = web.UAM
   655  	}
   656  
   657  	// CC
   658  	if web.CC != nil && (web.CC.IsPrior || isTop) {
   659  		this.web.CC = web.CC
   660  	}
   661  
   662  	// HLS
   663  	if web.HLS != nil && (web.HLS.IsPrior || isTop) {
   664  		this.web.HLS = web.HLS
   665  	}
   666  
   667  	// 重写规则
   668  	if len(web.RewriteRefs) > 0 {
   669  		for index, ref := range web.RewriteRefs {
   670  			if !ref.IsOn {
   671  				continue
   672  			}
   673  			rewriteRule := web.RewriteRules[index]
   674  			if !rewriteRule.IsOn {
   675  				continue
   676  			}
   677  			if replace, varMapping, isMatched := rewriteRule.MatchRequest(rawPath, this.Format); isMatched {
   678  				this.addVarMapping(varMapping)
   679  				this.rewriteRule = rewriteRule
   680  
   681  				if rewriteRule.WithQuery {
   682  					queryIndex := strings.Index(replace, "?")
   683  					if queryIndex > -1 {
   684  						if len(rawQuery) > 0 {
   685  							replace = replace[:queryIndex] + "?" + rawQuery + "&" + replace[queryIndex+1:]
   686  						}
   687  					} else {
   688  						if len(rawQuery) > 0 {
   689  							replace += "?" + rawQuery
   690  						}
   691  					}
   692  				}
   693  
   694  				this.rewriteReplace = replace
   695  
   696  				// 如果是外部URL直接返回
   697  				if rewriteRule.IsExternalURL(replace) {
   698  					this.rewriteIsExternalURL = true
   699  					return nil
   700  				}
   701  
   702  				// 如果是内部URL继续解析
   703  				if replace == this.uri {
   704  					// URL不变,则停止解析,防止无限循环跳转
   705  					return nil
   706  				}
   707  				this.uri = replace
   708  
   709  				// 终止解析的几个个条件:
   710  				//    isBreak = true
   711  				//    mode = redirect
   712  				//    replace = external url
   713  				//    replace = uri
   714  				if rewriteRule.IsBreak || rewriteRule.Mode == serverconfigs.HTTPRewriteModeRedirect {
   715  					return nil
   716  				}
   717  
   718  				return this.configureWeb(web, isTop, redirects+1)
   719  			}
   720  		}
   721  	}
   722  
   723  	// locations
   724  	if len(web.LocationRefs) > 0 {
   725  		var resultLocation *serverconfigs.HTTPLocationConfig
   726  		for index, ref := range web.LocationRefs {
   727  			if !ref.IsOn {
   728  				continue
   729  			}
   730  			location := web.Locations[index]
   731  			if !location.IsOn {
   732  				continue
   733  			}
   734  			if varMapping, isMatched := location.Match(rawPath, this.Format); isMatched {
   735  				// 检查专属域名
   736  				if len(location.Domains) > 0 && !configutils.MatchDomains(location.Domains, this.ReqHost) {
   737  					continue
   738  				}
   739  
   740  				if len(varMapping) > 0 {
   741  					this.addVarMapping(varMapping)
   742  				}
   743  				resultLocation = location
   744  
   745  				if location.IsBreak {
   746  					break
   747  				}
   748  			}
   749  		}
   750  		if resultLocation != nil {
   751  			// reset rewrite rule
   752  			this.rewriteRule = nil
   753  
   754  			// Reverse Proxy
   755  			if resultLocation.ReverseProxyRef != nil && resultLocation.ReverseProxyRef.IsPrior {
   756  				this.reverseProxyRef = resultLocation.ReverseProxyRef
   757  				this.reverseProxy = resultLocation.ReverseProxy
   758  			}
   759  
   760  			// Web
   761  			if resultLocation.Web != nil {
   762  				err := this.configureWeb(resultLocation.Web, false, redirects+1)
   763  				if err != nil {
   764  					return err
   765  				}
   766  			}
   767  		}
   768  	}
   769  
   770  	return nil
   771  }
   772  
   773  // Format 利用请求参数格式化字符串
   774  func (this *HTTPRequest) Format(source string) string {
   775  	if len(source) == 0 {
   776  		return ""
   777  	}
   778  
   779  	var hasVarMapping = len(this.varMapping) > 0
   780  
   781  	return configutils.ParseVariables(source, func(varName string) string {
   782  		// 自定义变量
   783  		if hasVarMapping {
   784  			value, found := this.varMapping[varName]
   785  			if found {
   786  				return value
   787  			}
   788  		}
   789  
   790  		// 请求变量
   791  		switch varName {
   792  		case "edgeVersion":
   793  			return teaconst.Version
   794  		case "remoteAddr":
   795  			return this.requestRemoteAddr(true)
   796  		case "remoteAddrValue":
   797  			return this.requestRemoteAddr(false)
   798  		case "rawRemoteAddr":
   799  			var addr = this.RawReq.RemoteAddr
   800  			host, _, err := net.SplitHostPort(addr)
   801  			if err == nil {
   802  				addr = host
   803  			}
   804  			return addr
   805  		case "remotePort":
   806  			return strconv.Itoa(this.requestRemotePort())
   807  		case "remoteUser":
   808  			return this.requestRemoteUser()
   809  		case "requestId":
   810  			return this.requestId
   811  		case "requestURI", "requestUri":
   812  			return this.rawURI
   813  		case "requestURL":
   814  			var scheme = "http"
   815  			if this.IsHTTPS {
   816  				scheme = "https"
   817  			}
   818  			return scheme + "://" + this.ReqHost + this.rawURI
   819  		case "requestPath":
   820  			return this.Path()
   821  		case "requestPathExtension":
   822  			return filepath.Ext(this.Path())
   823  		case "requestPathLowerExtension":
   824  			return strings.ToLower(filepath.Ext(this.Path()))
   825  		case "requestLength":
   826  			return strconv.FormatInt(this.requestLength(), 10)
   827  		case "requestTime":
   828  			return fmt.Sprintf("%.6f", this.requestCost)
   829  		case "requestMethod":
   830  			if len(this.RawReq.Method) == 0 {
   831  				return http.MethodGet
   832  			}
   833  			return this.RawReq.Method
   834  		case "requestFilename":
   835  			filename := this.requestFilename()
   836  			if len(filename) > 0 {
   837  				return filename
   838  			}
   839  
   840  			if this.web.Root != nil && this.web.Root.IsOn {
   841  				return filepath.Clean(this.web.Root.Dir + this.Path())
   842  			}
   843  
   844  			return ""
   845  		case "scheme":
   846  			if this.IsHTTP {
   847  				return "http"
   848  			} else {
   849  				return "https"
   850  			}
   851  		case "serverProtocol", "proto":
   852  			return this.RawReq.Proto
   853  		case "bytesSent":
   854  			return strconv.FormatInt(this.writer.SentBodyBytes(), 10) // TODO 加上Header长度
   855  		case "bodyBytesSent":
   856  			return strconv.FormatInt(this.writer.SentBodyBytes(), 10)
   857  		case "status":
   858  			return strconv.Itoa(this.writer.StatusCode())
   859  		case "statusMessage":
   860  			return http.StatusText(this.writer.StatusCode())
   861  		case "timeISO8601":
   862  			return this.requestFromTime.Format("2006-01-02T15:04:05.000Z07:00")
   863  		case "timeLocal":
   864  			return this.requestFromTime.Format("2/Jan/2006:15:04:05 -0700")
   865  		case "msec":
   866  			return fmt.Sprintf("%.6f", float64(this.requestFromTime.Unix())+float64(this.requestFromTime.Nanosecond())/1000000000)
   867  		case "timestamp":
   868  			return strconv.FormatInt(this.requestFromTime.Unix(), 10)
   869  		case "host":
   870  			return this.ReqHost
   871  		case "cname":
   872  			return this.ReqServer.CNameDomain
   873  		case "referer":
   874  			return this.RawReq.Referer()
   875  		case "referer.host":
   876  			u, err := url.Parse(this.RawReq.Referer())
   877  			if err == nil {
   878  				return u.Host
   879  			}
   880  			return ""
   881  		case "userAgent":
   882  			return this.RawReq.UserAgent()
   883  		case "contentType":
   884  			return this.requestContentType()
   885  		case "request":
   886  			return this.requestString()
   887  		case "cookies":
   888  			return this.requestCookiesString()
   889  		case "isArgs":
   890  			if strings.Contains(this.uri, "?") {
   891  				return "?"
   892  			}
   893  			return ""
   894  		case "args", "queryString":
   895  			return this.requestQueryString()
   896  		case "headers":
   897  			return this.requestHeadersString()
   898  		case "serverName":
   899  			return this.ServerName
   900  		case "serverAddr":
   901  			var nodeConfig = this.nodeConfig
   902  			if nodeConfig != nil && nodeConfig.GlobalServerConfig != nil && nodeConfig.GlobalServerConfig.HTTPAll.EnableServerAddrVariable {
   903  				if len(this.requestRemoteAddrs()) > 1 {
   904  					return "" // hidden for security
   905  				}
   906  				var requestConn = this.RawReq.Context().Value(HTTPConnContextKey)
   907  				if requestConn != nil {
   908  					conn, ok := requestConn.(net.Conn)
   909  					if ok {
   910  						host, _, _ := net.SplitHostPort(conn.LocalAddr().String())
   911  						if len(host) > 0 {
   912  							return host
   913  						}
   914  					}
   915  				}
   916  			}
   917  			return ""
   918  		case "serverPort":
   919  			return strconv.Itoa(this.requestServerPort())
   920  		case "hostname":
   921  			return HOSTNAME
   922  		case "documentRoot":
   923  			if this.web.Root != nil {
   924  				return this.web.Root.Dir
   925  			}
   926  			return ""
   927  		}
   928  
   929  		dotIndex := strings.Index(varName, ".")
   930  		if dotIndex < 0 {
   931  			return "${" + varName + "}"
   932  		}
   933  		prefix := varName[:dotIndex]
   934  		suffix := varName[dotIndex+1:]
   935  
   936  		// cookie.
   937  		if prefix == "cookie" {
   938  			return this.requestCookie(suffix)
   939  		}
   940  
   941  		// arg.
   942  		if prefix == "arg" {
   943  			return this.requestQueryParam(suffix)
   944  		}
   945  
   946  		// header.
   947  		if prefix == "header" || prefix == "http" {
   948  			return this.requestHeader(suffix)
   949  		}
   950  
   951  		// response.
   952  		if prefix == "response" {
   953  			switch suffix {
   954  			case "contentType":
   955  				return this.writer.Header().Get("Content-Type")
   956  			}
   957  
   958  			// response.xxx.xxx
   959  			dotIndex = strings.Index(suffix, ".")
   960  			if dotIndex < 0 {
   961  				return "${" + varName + "}"
   962  			}
   963  			switch suffix[:dotIndex] {
   964  			case "header":
   965  				var headers = this.writer.Header()
   966  				var headerKey = suffix[dotIndex+1:]
   967  				v, found := headers[headerKey]
   968  				if found {
   969  					if len(v) == 0 {
   970  						return ""
   971  					}
   972  					return v[0]
   973  				}
   974  				var canonicalHeaderKey = http.CanonicalHeaderKey(headerKey)
   975  				if canonicalHeaderKey != headerKey {
   976  					v = headers[canonicalHeaderKey]
   977  					if len(v) > 0 {
   978  						return v[0]
   979  					}
   980  				}
   981  				return ""
   982  			}
   983  		}
   984  
   985  		// origin.
   986  		if prefix == "origin" {
   987  			if this.origin != nil {
   988  				switch suffix {
   989  				case "address", "addr":
   990  					return this.originAddr
   991  				case "host":
   992  					addr := this.originAddr
   993  					index := strings.Index(addr, ":")
   994  					if index > -1 {
   995  						return addr[:index]
   996  					} else {
   997  						return ""
   998  					}
   999  				case "id":
  1000  					return strconv.FormatInt(this.origin.Id, 10)
  1001  				case "scheme", "protocol":
  1002  					return this.origin.Addr.Protocol.String()
  1003  				case "code":
  1004  					return this.origin.Code
  1005  				}
  1006  			}
  1007  			return ""
  1008  		}
  1009  
  1010  		// node
  1011  		if prefix == "node" {
  1012  			switch suffix {
  1013  			case "id":
  1014  				return strconv.FormatInt(this.nodeConfig.Id, 10)
  1015  			case "name":
  1016  				return this.nodeConfig.Name
  1017  			case "role":
  1018  				return teaconst.Role
  1019  			}
  1020  		}
  1021  
  1022  		// host
  1023  		if prefix == "host" {
  1024  			pieces := strings.Split(this.ReqHost, ".")
  1025  			switch suffix {
  1026  			case "first":
  1027  				if len(pieces) > 0 {
  1028  					return pieces[0]
  1029  				}
  1030  				return ""
  1031  			case "last":
  1032  				if len(pieces) > 0 {
  1033  					return pieces[len(pieces)-1]
  1034  				}
  1035  				return ""
  1036  			case "0":
  1037  				if len(pieces) > 0 {
  1038  					return pieces[0]
  1039  				}
  1040  				return ""
  1041  			case "1":
  1042  				if len(pieces) > 1 {
  1043  					return pieces[1]
  1044  				}
  1045  				return ""
  1046  			case "2":
  1047  				if len(pieces) > 2 {
  1048  					return pieces[2]
  1049  				}
  1050  				return ""
  1051  			case "3":
  1052  				if len(pieces) > 3 {
  1053  					return pieces[3]
  1054  				}
  1055  				return ""
  1056  			case "4":
  1057  				if len(pieces) > 4 {
  1058  					return pieces[4]
  1059  				}
  1060  				return ""
  1061  			case "-1":
  1062  				if len(pieces) > 0 {
  1063  					return pieces[len(pieces)-1]
  1064  				}
  1065  				return ""
  1066  			case "-2":
  1067  				if len(pieces) > 1 {
  1068  					return pieces[len(pieces)-2]
  1069  				}
  1070  				return ""
  1071  			case "-3":
  1072  				if len(pieces) > 2 {
  1073  					return pieces[len(pieces)-3]
  1074  				}
  1075  				return ""
  1076  			case "-4":
  1077  				if len(pieces) > 3 {
  1078  					return pieces[len(pieces)-4]
  1079  				}
  1080  				return ""
  1081  			case "-5":
  1082  				if len(pieces) > 4 {
  1083  					return pieces[len(pieces)-5]
  1084  				}
  1085  				return ""
  1086  			}
  1087  		}
  1088  
  1089  		// geo
  1090  		if prefix == "geo" {
  1091  			var result = iplib.LookupIP(this.requestRemoteAddr(true))
  1092  
  1093  			switch suffix {
  1094  			case "country.name":
  1095  				if result != nil && result.IsOk() {
  1096  					return result.CountryName()
  1097  				}
  1098  				return ""
  1099  			case "country.id":
  1100  				if result != nil && result.IsOk() {
  1101  					return types.String(result.CountryId())
  1102  				}
  1103  				return "0"
  1104  			case "province.name":
  1105  				if result != nil && result.IsOk() {
  1106  					return result.ProvinceName()
  1107  				}
  1108  				return ""
  1109  			case "province.id":
  1110  				if result != nil && result.IsOk() {
  1111  					return types.String(result.ProvinceId())
  1112  				}
  1113  				return "0"
  1114  			case "city.name":
  1115  				if result != nil && result.IsOk() {
  1116  					return result.CityName()
  1117  				}
  1118  				return ""
  1119  			case "city.id":
  1120  				if result != nil && result.IsOk() {
  1121  					return types.String(result.CityId())
  1122  				}
  1123  				return "0"
  1124  			case "town.name":
  1125  				if result != nil && result.IsOk() {
  1126  					return result.TownName()
  1127  				}
  1128  				return ""
  1129  			case "town.id":
  1130  				if result != nil && result.IsOk() {
  1131  					return types.String(result.TownId())
  1132  				}
  1133  				return "0"
  1134  			}
  1135  		}
  1136  
  1137  		// ips
  1138  		if prefix == "isp" {
  1139  			var result = iplib.LookupIP(this.requestRemoteAddr(true))
  1140  
  1141  			switch suffix {
  1142  			case "name":
  1143  				if result != nil && result.IsOk() {
  1144  					return result.ProviderName()
  1145  				}
  1146  			case "id":
  1147  				if result != nil && result.IsOk() {
  1148  					return types.String(result.ProviderId())
  1149  				}
  1150  				return "0"
  1151  			}
  1152  			return ""
  1153  		}
  1154  
  1155  		// browser
  1156  		if prefix == "browser" {
  1157  			var result = stats.SharedUserAgentParser.Parse(this.RawReq.UserAgent())
  1158  			switch suffix {
  1159  			case "os.name":
  1160  				return result.OS.Name
  1161  			case "os.version":
  1162  				return result.OS.Version
  1163  			case "name":
  1164  				return result.BrowserName
  1165  			case "version":
  1166  				return result.BrowserVersion
  1167  			case "isMobile":
  1168  				if result.IsMobile {
  1169  					return "1"
  1170  				} else {
  1171  					return "0"
  1172  				}
  1173  			}
  1174  		}
  1175  
  1176  		// product
  1177  		if prefix == "product" {
  1178  			switch suffix {
  1179  			case "name":
  1180  				if this.nodeConfig.ProductConfig != nil && len(this.nodeConfig.ProductConfig.Name) > 0 {
  1181  					return this.nodeConfig.ProductConfig.Name
  1182  				}
  1183  				return teaconst.GlobalProductName
  1184  			case "version":
  1185  				if this.nodeConfig.ProductConfig != nil && len(this.nodeConfig.ProductConfig.Version) > 0 {
  1186  					return this.nodeConfig.ProductConfig.Version
  1187  				}
  1188  				return teaconst.Version
  1189  			}
  1190  		}
  1191  
  1192  		return "${" + varName + "}"
  1193  	})
  1194  }
  1195  
  1196  // 添加变量定义
  1197  func (this *HTTPRequest) addVarMapping(varMapping map[string]string) {
  1198  	for k, v := range varMapping {
  1199  		this.varMapping[k] = v
  1200  	}
  1201  }
  1202  
  1203  // 获取请求的客户端地址
  1204  func (this *HTTPRequest) requestRemoteAddr(supportVar bool) string {
  1205  	if len(this.lnRemoteAddr) > 0 {
  1206  		return this.lnRemoteAddr
  1207  	}
  1208  
  1209  	if supportVar && len(this.remoteAddr) > 0 {
  1210  		return this.remoteAddr
  1211  	}
  1212  
  1213  	if supportVar &&
  1214  		this.web.RemoteAddr != nil &&
  1215  		this.web.RemoteAddr.IsOn &&
  1216  		!this.web.RemoteAddr.IsEmpty() {
  1217  		if this.web.RemoteAddr.HasValues() { // multiple values
  1218  			for _, value := range this.web.RemoteAddr.Values() {
  1219  				var remoteAddr = this.Format(value)
  1220  				if len(remoteAddr) > 0 && net.ParseIP(remoteAddr) != nil {
  1221  					this.remoteAddr = remoteAddr
  1222  					return remoteAddr
  1223  				}
  1224  			}
  1225  		} else { // single value
  1226  			var remoteAddr = this.Format(this.web.RemoteAddr.Value)
  1227  			if len(remoteAddr) > 0 && net.ParseIP(remoteAddr) != nil {
  1228  				this.remoteAddr = remoteAddr
  1229  				return remoteAddr
  1230  			}
  1231  		}
  1232  
  1233  		// 如果是从Header中读取,则直接返回原始IP
  1234  		if this.web.RemoteAddr.Type == serverconfigs.HTTPRemoteAddrTypeRequestHeader {
  1235  			var remoteAddr = this.RawReq.RemoteAddr
  1236  			host, _, err := net.SplitHostPort(remoteAddr)
  1237  			if err == nil {
  1238  				this.remoteAddr = host
  1239  				return host
  1240  			} else {
  1241  				return remoteAddr
  1242  			}
  1243  		}
  1244  	}
  1245  
  1246  	// X-Forwarded-For
  1247  	var forwardedFor = this.RawReq.Header.Get("X-Forwarded-For")
  1248  	if len(forwardedFor) > 0 {
  1249  		commaIndex := strings.Index(forwardedFor, ",")
  1250  		if commaIndex > 0 {
  1251  			forwardedFor = forwardedFor[:commaIndex]
  1252  		}
  1253  		if net.ParseIP(forwardedFor) != nil {
  1254  			if supportVar {
  1255  				this.remoteAddr = forwardedFor
  1256  			}
  1257  			return forwardedFor
  1258  		}
  1259  	}
  1260  
  1261  	// Real-IP
  1262  	{
  1263  		realIP, ok := this.RawReq.Header["X-Real-IP"]
  1264  		if ok && len(realIP) > 0 {
  1265  			if net.ParseIP(realIP[0]) != nil {
  1266  				if supportVar {
  1267  					this.remoteAddr = realIP[0]
  1268  				}
  1269  				return realIP[0]
  1270  			}
  1271  		}
  1272  	}
  1273  
  1274  	// Real-Ip
  1275  	{
  1276  		realIP, ok := this.RawReq.Header["X-Real-Ip"]
  1277  		if ok && len(realIP) > 0 {
  1278  			if net.ParseIP(realIP[0]) != nil {
  1279  				if supportVar {
  1280  					this.remoteAddr = realIP[0]
  1281  				}
  1282  				return realIP[0]
  1283  			}
  1284  		}
  1285  	}
  1286  
  1287  	// Remote-Addr
  1288  	var remoteAddr = this.RawReq.RemoteAddr
  1289  	host, _, err := net.SplitHostPort(remoteAddr)
  1290  	if err == nil {
  1291  		if supportVar {
  1292  			this.remoteAddr = host
  1293  		}
  1294  		return host
  1295  	} else {
  1296  		return remoteAddr
  1297  	}
  1298  }
  1299  
  1300  // 获取请求的客户端地址列表
  1301  func (this *HTTPRequest) requestRemoteAddrs() (result []string) {
  1302  	result = append(result, this.requestRemoteAddr(true))
  1303  
  1304  	// X-Forwarded-For
  1305  	var forwardedFor = this.RawReq.Header.Get("X-Forwarded-For")
  1306  	if len(forwardedFor) > 0 {
  1307  		commaIndex := strings.Index(forwardedFor, ",")
  1308  		if commaIndex > 0 && !lists.ContainsString(result, forwardedFor[:commaIndex]) {
  1309  			result = append(result, forwardedFor[:commaIndex])
  1310  		}
  1311  	}
  1312  
  1313  	// Real-IP
  1314  	{
  1315  		realIP, ok := this.RawReq.Header["X-Real-IP"]
  1316  		if ok && len(realIP) > 0 && !lists.ContainsString(result, realIP[0]) {
  1317  			result = append(result, realIP[0])
  1318  		}
  1319  	}
  1320  
  1321  	// Real-Ip
  1322  	{
  1323  		realIP, ok := this.RawReq.Header["X-Real-Ip"]
  1324  		if ok && len(realIP) > 0 && !lists.ContainsString(result, realIP[0]) {
  1325  			result = append(result, realIP[0])
  1326  		}
  1327  	}
  1328  
  1329  	// Remote-Addr
  1330  	{
  1331  		var remoteAddr = this.RawReq.RemoteAddr
  1332  		host, _, err := net.SplitHostPort(remoteAddr)
  1333  		if err == nil {
  1334  			if !lists.ContainsString(result, host) {
  1335  				result = append(result, host)
  1336  			}
  1337  		} else {
  1338  			result = append(result, remoteAddr)
  1339  		}
  1340  	}
  1341  
  1342  	return
  1343  }
  1344  
  1345  // 请求内容长度
  1346  func (this *HTTPRequest) requestLength() int64 {
  1347  	return this.RawReq.ContentLength
  1348  }
  1349  
  1350  // 请求用户
  1351  func (this *HTTPRequest) requestRemoteUser() string {
  1352  	username, _, ok := this.RawReq.BasicAuth()
  1353  	if !ok {
  1354  		return ""
  1355  	}
  1356  	return username
  1357  }
  1358  
  1359  // Path 请求的URL中路径部分
  1360  func (this *HTTPRequest) Path() string {
  1361  	uri, err := url.ParseRequestURI(this.uri)
  1362  	if err != nil {
  1363  		return ""
  1364  	}
  1365  	return uri.Path
  1366  }
  1367  
  1368  // 客户端端口
  1369  func (this *HTTPRequest) requestRemotePort() int {
  1370  	_, port, err := net.SplitHostPort(this.RawReq.RemoteAddr)
  1371  	if err == nil {
  1372  		return types.Int(port)
  1373  	}
  1374  	return 0
  1375  }
  1376  
  1377  // 获取的URI中的参数部分
  1378  func (this *HTTPRequest) requestQueryString() string {
  1379  	uri, err := url.ParseRequestURI(this.uri)
  1380  	if err != nil {
  1381  		return ""
  1382  	}
  1383  	return uri.RawQuery
  1384  }
  1385  
  1386  // 构造类似于"GET / HTTP/1.1"之类的请求字符串
  1387  func (this *HTTPRequest) requestString() string {
  1388  	return this.RawReq.Method + " " + this.rawURI + " " + this.RawReq.Proto
  1389  }
  1390  
  1391  // 构造请求字符串
  1392  func (this *HTTPRequest) requestCookiesString() string {
  1393  	var cookies = []string{}
  1394  	for _, cookie := range this.RawReq.Cookies() {
  1395  		cookies = append(cookies, url.QueryEscape(cookie.Name)+"="+url.QueryEscape(cookie.Value))
  1396  	}
  1397  	return strings.Join(cookies, "&")
  1398  }
  1399  
  1400  // 查询单个Cookie值
  1401  func (this *HTTPRequest) requestCookie(name string) string {
  1402  	cookie, err := this.RawReq.Cookie(name)
  1403  	if err != nil {
  1404  		return ""
  1405  	}
  1406  	return cookie.Value
  1407  }
  1408  
  1409  // 查询请求参数值
  1410  func (this *HTTPRequest) requestQueryParam(name string) string {
  1411  	uri, err := url.ParseRequestURI(this.rawURI)
  1412  	if err != nil {
  1413  		return ""
  1414  	}
  1415  
  1416  	v, found := uri.Query()[name]
  1417  	if !found {
  1418  		return ""
  1419  	}
  1420  	return strings.Join(v, "&")
  1421  }
  1422  
  1423  // 查询单个请求Header值
  1424  func (this *HTTPRequest) requestHeader(key string) string {
  1425  	v, found := this.RawReq.Header[key]
  1426  	if !found {
  1427  		// 转换为canonical header再尝试
  1428  		var canonicalHeaderKey = http.CanonicalHeaderKey(key)
  1429  		if canonicalHeaderKey != key {
  1430  			return strings.Join(this.RawReq.Header[canonicalHeaderKey], ";")
  1431  		}
  1432  
  1433  		return ""
  1434  	}
  1435  	return strings.Join(v, ";")
  1436  }
  1437  
  1438  // 以字符串的形式返回所有请求Header
  1439  func (this *HTTPRequest) requestHeadersString() string {
  1440  	var headers = []string{}
  1441  	for k, v := range this.RawReq.Header {
  1442  		for _, subV := range v {
  1443  			headers = append(headers, k+": "+subV)
  1444  		}
  1445  	}
  1446  	return strings.Join(headers, ";")
  1447  }
  1448  
  1449  // 获取请求Content-Type值
  1450  func (this *HTTPRequest) requestContentType() string {
  1451  	return this.RawReq.Header.Get("Content-Type")
  1452  }
  1453  
  1454  // 获取请求的文件名,仅在请求是读取本地文件时不为空
  1455  func (this *HTTPRequest) requestFilename() string {
  1456  	return this.filePath
  1457  }
  1458  
  1459  // 请求的scheme
  1460  func (this *HTTPRequest) requestScheme() string {
  1461  	if this.IsHTTPS {
  1462  		return "https"
  1463  	}
  1464  	return "http"
  1465  }
  1466  
  1467  // 请求的服务器地址中的端口
  1468  func (this *HTTPRequest) requestServerPort() int {
  1469  	if len(this.ServerAddr) > 0 {
  1470  		_, port, err := net.SplitHostPort(this.ServerAddr)
  1471  		if err == nil && len(port) > 0 {
  1472  			return types.Int(port)
  1473  		}
  1474  	}
  1475  
  1476  	var host = this.RawReq.Host
  1477  	if len(host) > 0 {
  1478  		_, port, err := net.SplitHostPort(host)
  1479  		if err == nil && len(port) > 0 {
  1480  			return types.Int(port)
  1481  		}
  1482  	}
  1483  
  1484  	if this.IsHTTP {
  1485  		return 80
  1486  	}
  1487  	return 443
  1488  }
  1489  
  1490  func (this *HTTPRequest) Id() string {
  1491  	return this.requestId
  1492  }
  1493  
  1494  func (this *HTTPRequest) Server() maps.Map {
  1495  	return maps.Map{"id": this.ReqServer.Id}
  1496  }
  1497  
  1498  func (this *HTTPRequest) Node() maps.Map {
  1499  	return maps.Map{"id": teaconst.NodeId}
  1500  }
  1501  
  1502  // URL 获取完整的URL
  1503  func (this *HTTPRequest) URL() string {
  1504  	return this.requestScheme() + "://" + this.ReqHost + this.uri
  1505  }
  1506  
  1507  // Host 获取Host
  1508  func (this *HTTPRequest) Host() string {
  1509  	return this.ReqHost
  1510  }
  1511  
  1512  func (this *HTTPRequest) Proto() string {
  1513  	return this.RawReq.Proto
  1514  }
  1515  
  1516  func (this *HTTPRequest) ProtoMajor() int {
  1517  	return this.RawReq.ProtoMajor
  1518  }
  1519  
  1520  func (this *HTTPRequest) ProtoMinor() int {
  1521  	return this.RawReq.ProtoMinor
  1522  }
  1523  
  1524  func (this *HTTPRequest) RemoteAddr() string {
  1525  	return this.requestRemoteAddr(true)
  1526  }
  1527  
  1528  func (this *HTTPRequest) RawRemoteAddr() string {
  1529  	var addr = this.RawReq.RemoteAddr
  1530  	host, _, err := net.SplitHostPort(addr)
  1531  	if err == nil {
  1532  		addr = host
  1533  	}
  1534  	return addr
  1535  }
  1536  
  1537  func (this *HTTPRequest) RemotePort() int {
  1538  	addr := this.RawReq.RemoteAddr
  1539  	_, port, err := net.SplitHostPort(addr)
  1540  	if err != nil {
  1541  		return 0
  1542  	}
  1543  	return types.Int(port)
  1544  }
  1545  
  1546  func (this *HTTPRequest) SetAttr(name string, value string) {
  1547  	this.logAttrs[name] = value
  1548  }
  1549  
  1550  func (this *HTTPRequest) SetVar(name string, value string) {
  1551  	this.varMapping[name] = value
  1552  }
  1553  
  1554  // ContentLength 请求内容长度
  1555  func (this *HTTPRequest) ContentLength() int64 {
  1556  	return this.RawReq.ContentLength
  1557  }
  1558  
  1559  // CalculateSize 计算当前请求的尺寸(预估)
  1560  func (this *HTTPRequest) CalculateSize() (size int64) {
  1561  	// Get /xxx HTTP/1.1
  1562  	size += int64(len(this.RawReq.Method)) + 1
  1563  	size += int64(len(this.RawReq.URL.String())) + 1
  1564  	size += int64(len(this.RawReq.Proto)) + 1
  1565  	for k, v := range this.RawReq.Header {
  1566  		for _, v1 := range v {
  1567  			size += int64(len(k) + 2 /** : **/ + len(v1) + 1)
  1568  		}
  1569  	}
  1570  
  1571  	size += 1 /** \r\n **/
  1572  
  1573  	if this.RawReq.ContentLength > 0 {
  1574  		size += this.RawReq.ContentLength
  1575  	} else if len(this.requestBodyData) > 0 {
  1576  		size += int64(len(this.requestBodyData))
  1577  	}
  1578  	return size
  1579  }
  1580  
  1581  // Method 请求方法
  1582  func (this *HTTPRequest) Method() string {
  1583  	return this.RawReq.Method
  1584  }
  1585  
  1586  // TransferEncoding 获取传输编码
  1587  func (this *HTTPRequest) TransferEncoding() string {
  1588  	if len(this.RawReq.TransferEncoding) > 0 {
  1589  		return this.RawReq.TransferEncoding[0]
  1590  	}
  1591  	return ""
  1592  }
  1593  
  1594  // Cookie 获取Cookie
  1595  func (this *HTTPRequest) Cookie(name string) string {
  1596  	c, err := this.RawReq.Cookie(name)
  1597  	if err != nil {
  1598  		return ""
  1599  	}
  1600  	return c.Value
  1601  }
  1602  
  1603  // DeleteHeader 删除请求Header
  1604  func (this *HTTPRequest) DeleteHeader(name string) {
  1605  	this.RawReq.Header.Del(name)
  1606  }
  1607  
  1608  // SetHeader 设置请求Header
  1609  func (this *HTTPRequest) SetHeader(name string, values []string) {
  1610  	this.RawReq.Header[name] = values
  1611  }
  1612  
  1613  // Header 读取Header
  1614  func (this *HTTPRequest) Header() http.Header {
  1615  	return this.RawReq.Header
  1616  }
  1617  
  1618  // URI 获取当前请求的URI
  1619  func (this *HTTPRequest) URI() string {
  1620  	return this.uri
  1621  }
  1622  
  1623  // SetURI 设置当前请求的URI
  1624  func (this *HTTPRequest) SetURI(uri string) {
  1625  	this.uri = uri
  1626  }
  1627  
  1628  // Done 设置已完成
  1629  func (this *HTTPRequest) Done() {
  1630  	this.isDone = true
  1631  }
  1632  
  1633  // Close 关闭连接
  1634  func (this *HTTPRequest) Close() {
  1635  	this.Done()
  1636  
  1637  	var requestConn = this.RawReq.Context().Value(HTTPConnContextKey)
  1638  	if requestConn == nil {
  1639  		return
  1640  	}
  1641  
  1642  	lingerConn, ok := requestConn.(LingerConn)
  1643  	if ok {
  1644  		_ = lingerConn.SetLinger(0)
  1645  	}
  1646  
  1647  	conn, ok := requestConn.(net.Conn)
  1648  	if ok {
  1649  		_ = conn.Close()
  1650  		return
  1651  	}
  1652  }
  1653  
  1654  // Allow 放行
  1655  func (this *HTTPRequest) Allow() {
  1656  	this.web.FirewallRef = nil
  1657  }
  1658  
  1659  // 设置代理相关头部信息
  1660  // 参考:https://tools.ietf.org/html/rfc7239
  1661  func (this *HTTPRequest) setForwardHeaders(header http.Header) {
  1662  	// TODO 做成可选项
  1663  	if this.RawReq.Header.Get("Connection") == "close" {
  1664  		this.RawReq.Header.Set("Connection", "keep-alive")
  1665  	}
  1666  
  1667  	var rawRemoteAddr = this.RawReq.RemoteAddr
  1668  	host, _, err := net.SplitHostPort(rawRemoteAddr)
  1669  	if err == nil {
  1670  		rawRemoteAddr = host
  1671  	}
  1672  
  1673  	// x-real-ip
  1674  	if this.reverseProxy != nil && this.reverseProxy.ShouldAddXRealIPHeader() {
  1675  		_, ok1 := header["X-Real-IP"]
  1676  		_, ok2 := header["X-Real-Ip"]
  1677  		if !ok1 && !ok2 {
  1678  			header["X-Real-IP"] = []string{this.requestRemoteAddr(true)}
  1679  		}
  1680  	}
  1681  
  1682  	// X-Forwarded-For
  1683  	if this.reverseProxy != nil && this.reverseProxy.ShouldAddXForwardedForHeader() {
  1684  		forwardedFor, ok := header["X-Forwarded-For"]
  1685  		if ok && len(forwardedFor) > 0 { // already exists
  1686  			_, hasForwardHeader := this.RawReq.Header["X-Forwarded-For"]
  1687  			if hasForwardHeader {
  1688  				header["X-Forwarded-For"] = []string{strings.Join(forwardedFor, ", ") + ", " + rawRemoteAddr}
  1689  			}
  1690  		} else {
  1691  			var clientRemoteAddr = this.requestRemoteAddr(true)
  1692  			if len(clientRemoteAddr) > 0 && clientRemoteAddr != rawRemoteAddr {
  1693  				header["X-Forwarded-For"] = []string{clientRemoteAddr + ", " + rawRemoteAddr}
  1694  			} else {
  1695  				header["X-Forwarded-For"] = []string{rawRemoteAddr}
  1696  			}
  1697  		}
  1698  	}
  1699  
  1700  	// Forwarded
  1701  	/**{
  1702  		forwarded, ok := header["Forwarded"]
  1703  		if ok {
  1704  			header["Forwarded"] = []string{strings.Join(forwarded, ", ") + ", by=" + this.serverAddr + "; for=" + remoteAddr + "; host=" + this.ReqHost + "; proto=" + this.rawScheme}
  1705  		} else {
  1706  			header["Forwarded"] = []string{"by=" + this.serverAddr + "; for=" + remoteAddr + "; host=" + this.ReqHost + "; proto=" + this.rawScheme}
  1707  		}
  1708  	}**/
  1709  
  1710  	// others
  1711  	if this.reverseProxy != nil && this.reverseProxy.ShouldAddXForwardedByHeader() {
  1712  		this.RawReq.Header.Set("X-Forwarded-By", this.ServerAddr)
  1713  	}
  1714  
  1715  	if this.reverseProxy != nil && this.reverseProxy.ShouldAddXForwardedHostHeader() {
  1716  		if _, ok := header["X-Forwarded-Host"]; !ok {
  1717  			this.RawReq.Header.Set("X-Forwarded-Host", this.ReqHost)
  1718  		}
  1719  	}
  1720  
  1721  	if this.reverseProxy != nil && this.reverseProxy.ShouldAddXForwardedProtoHeader() {
  1722  		if _, ok := header["X-Forwarded-Proto"]; !ok {
  1723  			this.RawReq.Header.Set("X-Forwarded-Proto", this.requestScheme())
  1724  		}
  1725  	}
  1726  }
  1727  
  1728  // 处理自定义Request Header
  1729  func (this *HTTPRequest) processRequestHeaders(reqHeader http.Header) {
  1730  	this.fixRequestHeader(reqHeader)
  1731  
  1732  	if this.web.RequestHeaderPolicy != nil && this.web.RequestHeaderPolicy.IsOn {
  1733  		// 删除某些Header
  1734  		for name := range reqHeader {
  1735  			if this.web.RequestHeaderPolicy.ContainsDeletedHeader(name) {
  1736  				reqHeader.Del(name)
  1737  			}
  1738  		}
  1739  
  1740  		// Set
  1741  		for _, header := range this.web.RequestHeaderPolicy.SetHeaders {
  1742  			if !header.IsOn {
  1743  				continue
  1744  			}
  1745  
  1746  			// 是否已删除
  1747  			if this.web.RequestHeaderPolicy.ContainsDeletedHeader(header.Name) {
  1748  				continue
  1749  			}
  1750  
  1751  			// 请求方法
  1752  			if len(header.Methods) > 0 && !lists.ContainsString(header.Methods, this.RawReq.Method) {
  1753  				continue
  1754  			}
  1755  
  1756  			// 域名
  1757  			if len(header.Domains) > 0 && !configutils.MatchDomains(header.Domains, this.ReqHost) {
  1758  				continue
  1759  			}
  1760  
  1761  			var headerValue = header.Value
  1762  			if header.ShouldReplace {
  1763  				if len(headerValue) == 0 {
  1764  					headerValue = reqHeader.Get(header.Name) // 原有值
  1765  				} else if header.HasVariables() {
  1766  					headerValue = this.Format(header.Value)
  1767  				}
  1768  
  1769  				for _, v := range header.ReplaceValues {
  1770  					headerValue = v.Replace(headerValue)
  1771  				}
  1772  			} else if header.HasVariables() {
  1773  				headerValue = this.Format(header.Value)
  1774  			}
  1775  
  1776  			// 支持修改Host
  1777  			if header.Name == "Host" && len(header.Value) > 0 {
  1778  				this.RawReq.Host = headerValue
  1779  			} else {
  1780  				if header.ShouldAppend {
  1781  					reqHeader[header.Name] = append(reqHeader[header.Name], headerValue)
  1782  				} else {
  1783  					reqHeader[header.Name] = []string{headerValue}
  1784  				}
  1785  			}
  1786  		}
  1787  
  1788  		// 非标Header
  1789  		if len(this.web.RequestHeaderPolicy.NonStandardHeaders) > 0 {
  1790  			for _, name := range this.web.RequestHeaderPolicy.NonStandardHeaders {
  1791  				var canonicalKey = http.CanonicalHeaderKey(name)
  1792  				if canonicalKey != name {
  1793  					v, ok := reqHeader[canonicalKey]
  1794  					if ok {
  1795  						delete(reqHeader, canonicalKey)
  1796  						reqHeader[name] = v
  1797  					}
  1798  				}
  1799  			}
  1800  		}
  1801  	}
  1802  }
  1803  
  1804  // 处理一些被Golang转换了的Header
  1805  // TODO 可以自定义要转换的Header
  1806  func (this *HTTPRequest) fixRequestHeader(header http.Header) {
  1807  	for k, v := range header {
  1808  		if strings.Contains(k, "-Websocket-") {
  1809  			header.Del(k)
  1810  			k = strings.ReplaceAll(k, "-Websocket-", "-WebSocket-")
  1811  			header[k] = v
  1812  		} else if strings.HasPrefix(k, "Sec-Ch") {
  1813  			header.Del(k)
  1814  			k = strings.ReplaceAll(k, "Sec-Ch-Ua", "Sec-CH-UA")
  1815  			header[k] = v
  1816  		} else {
  1817  			switch k {
  1818  			case "Www-Authenticate":
  1819  				header.Del(k)
  1820  				header["WWW-Authenticate"] = v
  1821  			case "A-Im":
  1822  				header.Del(k)
  1823  				header["A-IM"] = v
  1824  			case "Content-Md5":
  1825  				header.Del(k)
  1826  				header["Content-MD5"] = v
  1827  			case "Sec-Gpc":
  1828  				header.Del(k)
  1829  				header["Content-GPC"] = v
  1830  			}
  1831  		}
  1832  	}
  1833  }
  1834  
  1835  // ProcessResponseHeaders 处理自定义Response Header
  1836  func (this *HTTPRequest) ProcessResponseHeaders(responseHeader http.Header, statusCode int) {
  1837  	// Server Name
  1838  	if this.nodeConfig != nil && this.nodeConfig.GlobalServerConfig != nil && len(this.nodeConfig.GlobalServerConfig.HTTPAll.ServerName) > 0 {
  1839  		responseHeader.Set("Server", this.nodeConfig.GlobalServerConfig.HTTPAll.ServerName)
  1840  	}
  1841  
  1842  	// 删除/添加/替换Header
  1843  	// TODO 实现AddTrailers
  1844  	if this.web.ResponseHeaderPolicy != nil && this.web.ResponseHeaderPolicy.IsOn {
  1845  		// 删除某些Header
  1846  		for name := range responseHeader {
  1847  			if this.web.ResponseHeaderPolicy.ContainsDeletedHeader(name) {
  1848  				responseHeader.Del(name)
  1849  			}
  1850  		}
  1851  
  1852  		// Set
  1853  		for _, header := range this.web.ResponseHeaderPolicy.SetHeaders {
  1854  			if !header.IsOn {
  1855  				continue
  1856  			}
  1857  
  1858  			// 是否已删除
  1859  			if this.web.ResponseHeaderPolicy.ContainsDeletedHeader(header.Name) {
  1860  				continue
  1861  			}
  1862  
  1863  			// 状态码
  1864  			if header.Status != nil && !header.Status.Match(statusCode) {
  1865  				continue
  1866  			}
  1867  
  1868  			// 请求方法
  1869  			if len(header.Methods) > 0 && !lists.ContainsString(header.Methods, this.RawReq.Method) {
  1870  				continue
  1871  			}
  1872  
  1873  			// 域名
  1874  			if len(header.Domains) > 0 && !configutils.MatchDomains(header.Domains, this.ReqHost) {
  1875  				continue
  1876  			}
  1877  
  1878  			// 是否为跳转
  1879  			if header.DisableRedirect && httpStatusIsRedirect(statusCode) {
  1880  				continue
  1881  			}
  1882  
  1883  			var headerValue = header.Value
  1884  			if header.ShouldReplace {
  1885  				if len(headerValue) == 0 {
  1886  					headerValue = responseHeader.Get(header.Name) // 原有值
  1887  				} else if header.HasVariables() {
  1888  					headerValue = this.Format(header.Value)
  1889  				}
  1890  
  1891  				for _, v := range header.ReplaceValues {
  1892  					headerValue = v.Replace(headerValue)
  1893  				}
  1894  			} else if header.HasVariables() {
  1895  				headerValue = this.Format(header.Value)
  1896  			}
  1897  
  1898  			if header.ShouldAppend {
  1899  				responseHeader[header.Name] = append(responseHeader[header.Name], headerValue)
  1900  			} else {
  1901  				responseHeader[header.Name] = []string{headerValue}
  1902  			}
  1903  		}
  1904  
  1905  		// 非标Header
  1906  		if len(this.web.ResponseHeaderPolicy.NonStandardHeaders) > 0 {
  1907  			for _, name := range this.web.ResponseHeaderPolicy.NonStandardHeaders {
  1908  				var canonicalKey = http.CanonicalHeaderKey(name)
  1909  				if canonicalKey != name {
  1910  					v, ok := responseHeader[canonicalKey]
  1911  					if ok {
  1912  						delete(responseHeader, canonicalKey)
  1913  						responseHeader[name] = v
  1914  					}
  1915  				}
  1916  			}
  1917  		}
  1918  
  1919  		// CORS
  1920  		if this.web.ResponseHeaderPolicy.CORS != nil && this.web.ResponseHeaderPolicy.CORS.IsOn && (!this.web.ResponseHeaderPolicy.CORS.OptionsMethodOnly || this.RawReq.Method == http.MethodOptions) {
  1921  			var corsConfig = this.web.ResponseHeaderPolicy.CORS
  1922  
  1923  			// Allow-Origin
  1924  			if len(corsConfig.AllowOrigin) == 0 {
  1925  				var origin = this.RawReq.Header.Get("Origin")
  1926  				if len(origin) > 0 {
  1927  					responseHeader.Set("Access-Control-Allow-Origin", origin)
  1928  				}
  1929  			} else {
  1930  				responseHeader.Set("Access-Control-Allow-Origin", corsConfig.AllowOrigin)
  1931  			}
  1932  
  1933  			// Allow-Methods
  1934  			if len(corsConfig.AllowMethods) == 0 {
  1935  				responseHeader.Set("Access-Control-Allow-Methods", "PUT, GET, POST, DELETE, HEAD, OPTIONS, PATCH")
  1936  			} else {
  1937  				responseHeader.Set("Access-Control-Allow-Methods", strings.Join(corsConfig.AllowMethods, ", "))
  1938  			}
  1939  
  1940  			// Max-Age
  1941  			if corsConfig.MaxAge > 0 {
  1942  				responseHeader.Set("Access-Control-Max-Age", types.String(corsConfig.MaxAge))
  1943  			}
  1944  
  1945  			// Expose-Headers
  1946  			if len(corsConfig.ExposeHeaders) > 0 {
  1947  				responseHeader.Set("Access-Control-Expose-Headers", strings.Join(corsConfig.ExposeHeaders, ", "))
  1948  			}
  1949  
  1950  			// Request-Method
  1951  			if len(corsConfig.RequestMethod) > 0 {
  1952  				responseHeader.Set("Access-Control-Request-Method", strings.ToUpper(corsConfig.RequestMethod))
  1953  			}
  1954  
  1955  			// Allow-Credentials
  1956  			responseHeader.Set("Access-Control-Allow-Credentials", "true")
  1957  		}
  1958  	}
  1959  
  1960  	// HSTS
  1961  	if this.IsHTTPS &&
  1962  		this.ReqServer.HTTPS != nil &&
  1963  		this.ReqServer.HTTPS.SSLPolicy != nil &&
  1964  		this.ReqServer.HTTPS.SSLPolicy.IsOn &&
  1965  		this.ReqServer.HTTPS.SSLPolicy.HSTS != nil &&
  1966  		this.ReqServer.HTTPS.SSLPolicy.HSTS.IsOn &&
  1967  		this.ReqServer.HTTPS.SSLPolicy.HSTS.Match(this.ReqHost) {
  1968  		responseHeader.Set(this.ReqServer.HTTPS.SSLPolicy.HSTS.HeaderKey(), this.ReqServer.HTTPS.SSLPolicy.HSTS.HeaderValue())
  1969  	}
  1970  
  1971  	// HTTP/3
  1972  	if this.IsHTTPS && !this.IsHTTP3 && this.ReqServer.SupportsHTTP3() {
  1973  		this.processHTTP3Headers(responseHeader)
  1974  	}
  1975  }
  1976  
  1977  // 添加错误信息
  1978  func (this *HTTPRequest) addError(err error) {
  1979  	if err == nil {
  1980  		return
  1981  	}
  1982  	this.errors = append(this.errors, err.Error())
  1983  }
  1984  
  1985  // 计算合适的buffer size
  1986  func (this *HTTPRequest) bytePool(contentLength int64) *utils.BytePool {
  1987  	if contentLength < 0 {
  1988  		return utils.BytePool16k
  1989  	}
  1990  	if contentLength < 8192 { // 8K
  1991  		return utils.BytePool1k
  1992  	}
  1993  	if contentLength < 32768 { // 32K
  1994  		return utils.BytePool16k
  1995  	}
  1996  	if contentLength < 131072 { // 128K
  1997  		return utils.BytePool32k
  1998  	}
  1999  	return utils.BytePool32k
  2000  }
  2001  
  2002  // 检查是否可以忽略错误
  2003  func (this *HTTPRequest) canIgnore(err error) bool {
  2004  	if err == nil {
  2005  		return true
  2006  	}
  2007  
  2008  	// 已读到头
  2009  	if err == io.EOF || err == io.ErrUnexpectedEOF {
  2010  		return true
  2011  	}
  2012  
  2013  	// 网络错误
  2014  	_, ok := err.(*net.OpError)
  2015  	if ok {
  2016  		return true
  2017  	}
  2018  
  2019  	// 客户端主动取消
  2020  	if err == errWritingToClient ||
  2021  		err == context.Canceled ||
  2022  		err == io.ErrShortWrite ||
  2023  		strings.Contains(err.Error(), "write: connection") ||
  2024  		strings.Contains(err.Error(), "write: broken pipe") ||
  2025  		strings.Contains(err.Error(), "write tcp") {
  2026  		return true
  2027  	}
  2028  
  2029  	// HTTP/2流错误
  2030  	if err.Error() == "http2: stream closed" || strings.Contains(err.Error(), "stream error") || err.Error() == "client disconnected" { // errStreamClosed, errClientDisconnected
  2031  		return true
  2032  	}
  2033  
  2034  	// HTTP内部错误
  2035  	if strings.HasPrefix(err.Error(), "http:") || strings.HasPrefix(err.Error(), "http2:") {
  2036  		return true
  2037  	}
  2038  
  2039  	return false
  2040  }
  2041  
  2042  // 检查连接是否已关闭
  2043  func (this *HTTPRequest) isConnClosed() bool {
  2044  	var requestConn = this.RawReq.Context().Value(HTTPConnContextKey)
  2045  	if requestConn == nil {
  2046  		return true
  2047  	}
  2048  
  2049  	conn, ok := requestConn.(net.Conn)
  2050  	if ok {
  2051  		return isClientConnClosed(conn)
  2052  	}
  2053  
  2054  	return true
  2055  }