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 }