81 lines
2.1 KiB
Go
81 lines
2.1 KiB
Go
package server
|
||
|
||
import (
|
||
"net"
|
||
"net/http"
|
||
"net/textproto"
|
||
"time"
|
||
|
||
"github.com/any-hub/any-hub/internal/config"
|
||
)
|
||
|
||
// Shared HTTP transport tunings,复用长连接并集中配置超时。
|
||
var defaultTransport = &http.Transport{
|
||
Proxy: http.ProxyFromEnvironment,
|
||
MaxIdleConns: 100,
|
||
MaxIdleConnsPerHost: 100,
|
||
IdleConnTimeout: 90 * time.Second,
|
||
TLSHandshakeTimeout: 10 * time.Second,
|
||
ExpectContinueTimeout: 1 * time.Second,
|
||
ForceAttemptHTTP2: true,
|
||
DialContext: (&net.Dialer{
|
||
Timeout: 30 * time.Second,
|
||
KeepAlive: 30 * time.Second,
|
||
}).DialContext,
|
||
}
|
||
|
||
// NewUpstreamClient 返回共享 http.Client,用于所有上游请求。
|
||
func NewUpstreamClient(cfg *config.Config) *http.Client {
|
||
timeout := 30 * time.Second
|
||
if cfg != nil && cfg.Global.UpstreamTimeout.DurationValue() > 0 {
|
||
timeout = cfg.Global.UpstreamTimeout.DurationValue()
|
||
}
|
||
|
||
transport := defaultTransport.Clone()
|
||
// Use UpstreamTimeout as ResponseHeaderTimeout to avoid killing long streaming downloads.
|
||
transport.ResponseHeaderTimeout = timeout
|
||
|
||
return &http.Client{
|
||
Transport: transport,
|
||
}
|
||
}
|
||
|
||
// hopByHopHeaders 定义 RFC 7230 中禁止代理转发的头部。
|
||
var hopByHopHeaders = map[string]struct{}{
|
||
"Connection": {},
|
||
"Keep-Alive": {},
|
||
"Proxy-Authenticate": {},
|
||
"Proxy-Authorization": {},
|
||
"Te": {},
|
||
"Trailer": {},
|
||
"Transfer-Encoding": {},
|
||
"Upgrade": {},
|
||
"Proxy-Connection": {}, // 非标准字段,但部分代理仍使用
|
||
}
|
||
|
||
// CopyHeaders 将 src 中允许透传的头复制到 dst,自动忽略 hop-by-hop 字段。
|
||
func CopyHeaders(dst, src http.Header) {
|
||
for key, values := range src {
|
||
if isHopByHopHeader(key) {
|
||
continue
|
||
}
|
||
for _, value := range values {
|
||
dst.Add(key, value)
|
||
}
|
||
}
|
||
}
|
||
|
||
func isHopByHopHeader(key string) bool {
|
||
canonical := textproto.CanonicalMIMEHeaderKey(key)
|
||
if _, ok := hopByHopHeaders[canonical]; ok {
|
||
return true
|
||
}
|
||
|
||
return false
|
||
}
|
||
|
||
// IsHopByHopHeader reports whether the header should be stripped by proxies.
|
||
func IsHopByHopHeader(key string) bool {
|
||
return isHopByHopHeader(key)
|
||
}
|