722dde5cfc
The readTimeout field (default 15s) was being applied via xnet.Pipe to both directions of a bidirectional proxy connection. During asymmetric transfers (e.g. HTTP file download), the direction reading from the tunnel sees no data after the initial request is forwarded, causing SetReadDeadline to fire after 15s and abort the entire transfer. Fix: add a separate idleTimeout field (default 0=disabled) to the metadata structs in both forward/local and forward/remote handlers, and switch xnet.Pipe to use idleTimeout instead of readTimeout. The readTimeout field now only applies to the initial protocol sniffing/handshake phase. Also document readTimeout vs idleTimeout semantics across all 24 locations in the x/ module where these timeouts appear: - readTimeout: handshake sniffing deadline (handlers), upstream response header timeout (http.Transport), or transport-level read deadline - idleTimeout: idle read deadline per Pipe direction (0=disabled) - ReadTimeout on Sniffer/SnifferBuilder: upstream response header/TLS handshake read timeout during sniffing
87 lines
2.6 KiB
Go
87 lines
2.6 KiB
Go
package router
|
|
|
|
import (
|
|
"time"
|
|
|
|
"github.com/go-gost/core/ingress"
|
|
mdata "github.com/go-gost/core/metadata"
|
|
"github.com/go-gost/core/router"
|
|
"github.com/go-gost/core/sd"
|
|
mdutil "github.com/go-gost/x/metadata/util"
|
|
"github.com/go-gost/x/registry"
|
|
)
|
|
|
|
const (
|
|
defaultTTL = 15 * time.Second
|
|
defaultBufferSize = 4096
|
|
defaultCacheExpiration = time.Second
|
|
)
|
|
|
|
type metadata struct {
|
|
// readTimeout is the deadline for reading the initial relay protocol
|
|
// handshake from the client connection. The deadline is cleared
|
|
// after the handshake, so it does not affect subsequent data
|
|
// transfer.
|
|
// 0 or negative means no timeout is applied.
|
|
readTimeout time.Duration
|
|
bufferSize int
|
|
|
|
entryPoint string
|
|
ingress ingress.Ingress
|
|
sd sd.SD
|
|
sdCacheExpiration time.Duration
|
|
sdRenewInterval time.Duration
|
|
|
|
router router.Router
|
|
routerCacheEnabled bool
|
|
routerCacheExpiration time.Duration
|
|
|
|
observerPeriod time.Duration
|
|
observerResetTraffic bool
|
|
|
|
limiterRefreshInterval time.Duration
|
|
limiterCleanupInterval time.Duration
|
|
}
|
|
|
|
func (h *routerHandler) parseMetadata(md mdata.Metadata) (err error) {
|
|
h.md.readTimeout = mdutil.GetDuration(md, "readTimeout")
|
|
h.md.bufferSize = mdutil.GetInt(md, "router.bufferSize", "bufferSize")
|
|
if h.md.bufferSize <= 0 {
|
|
h.md.bufferSize = defaultBufferSize
|
|
}
|
|
|
|
h.md.entryPoint = mdutil.GetString(md, "entrypoint")
|
|
h.md.ingress = registry.IngressRegistry().Get(mdutil.GetString(md, "ingress"))
|
|
|
|
h.md.sd = registry.SDRegistry().Get(mdutil.GetString(md, "sd"))
|
|
h.md.sdCacheExpiration = mdutil.GetDuration(md, "sd.cache.expiration")
|
|
if h.md.sdCacheExpiration <= 0 {
|
|
h.md.sdCacheExpiration = defaultCacheExpiration
|
|
}
|
|
h.md.sdRenewInterval = mdutil.GetDuration(md, "sd.renewInterval")
|
|
if h.md.sdRenewInterval < time.Second {
|
|
h.md.sdRenewInterval = defaultTTL
|
|
}
|
|
|
|
h.md.router = registry.RouterRegistry().Get(mdutil.GetString(md, "router"))
|
|
h.md.routerCacheEnabled = mdutil.GetBool(md, "router.cache")
|
|
h.md.routerCacheExpiration = mdutil.GetDuration(md, "router.cache.expiration")
|
|
if h.md.routerCacheExpiration <= 0 {
|
|
h.md.routerCacheExpiration = defaultCacheExpiration
|
|
}
|
|
|
|
h.md.observerPeriod = mdutil.GetDuration(md, "observePeriod", "observer.period", "observer.observePeriod")
|
|
if h.md.observerPeriod == 0 {
|
|
h.md.observerPeriod = 5 * time.Second
|
|
}
|
|
if h.md.observerPeriod < time.Second {
|
|
h.md.observerPeriod = time.Second
|
|
}
|
|
h.md.observerResetTraffic = mdutil.GetBool(md, "observer.resetTraffic")
|
|
|
|
h.md.limiterRefreshInterval = mdutil.GetDuration(md, "limiter.refreshInterval")
|
|
h.md.limiterCleanupInterval = mdutil.GetDuration(md, "limiter.cleanupInterval")
|
|
|
|
return
|
|
}
|