mirror of
https://github.com/therootcompany/golib.git
synced 2026-04-24 12:48:00 +00:00
fix: split connection and download timeouts in httpcache
ConnTimeout (default 5s) caps TCP connect + TLS handshake via net.Dialer and Transport.TLSHandshakeTimeout. Timeout (default 5m) caps the overall request including body read. Previously a single 30s timeout covered both, which was too short for large downloads and too long for connection failures.
This commit is contained in:
parent
86ffa2fb23
commit
d0a5e0a9d2
@ -3,13 +3,17 @@ package httpcache
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
const defaultTimeout = 30 * time.Second
|
||||
const (
|
||||
defaultConnTimeout = 5 * time.Second // TCP connect + TLS handshake
|
||||
defaultTimeout = 5 * time.Minute // overall including body read
|
||||
)
|
||||
|
||||
// Syncer is implemented by any value that can fetch a remote resource and
|
||||
// report whether it changed. Both *Cacher and *gitshallow.Repo satisfy this.
|
||||
@ -43,7 +47,8 @@ func (NopSyncer) Fetch() (bool, error) { return false, nil }
|
||||
type Cacher struct {
|
||||
URL string
|
||||
Path string
|
||||
Timeout time.Duration // 0 uses 30s
|
||||
ConnTimeout time.Duration // 0 uses 5s; caps TCP connect + TLS handshake
|
||||
Timeout time.Duration // 0 uses 5m; caps overall request including body read
|
||||
MaxAge time.Duration // 0 disables; skip HTTP if file mtime is within this
|
||||
MinInterval time.Duration // 0 disables; skip HTTP if last Fetch attempt was within this
|
||||
Username string // Basic Auth — not forwarded on redirects
|
||||
@ -86,6 +91,10 @@ func (c *Cacher) Fetch() (updated bool, err error) {
|
||||
}
|
||||
c.lastChecked = time.Now()
|
||||
|
||||
connTimeout := c.ConnTimeout
|
||||
if connTimeout == 0 {
|
||||
connTimeout = defaultConnTimeout
|
||||
}
|
||||
timeout := c.Timeout
|
||||
if timeout == 0 {
|
||||
timeout = defaultTimeout
|
||||
@ -102,20 +111,26 @@ func (c *Cacher) Fetch() (updated bool, err error) {
|
||||
req.Header.Set("If-Modified-Since", c.lastMod)
|
||||
}
|
||||
|
||||
transport := &http.Transport{
|
||||
DialContext: (&net.Dialer{Timeout: connTimeout}).DialContext,
|
||||
TLSHandshakeTimeout: connTimeout,
|
||||
}
|
||||
|
||||
var client *http.Client
|
||||
if c.Username != "" {
|
||||
req.SetBasicAuth(c.Username, c.Password)
|
||||
// Strip auth before following any redirect — presigned URLs (e.g. R2)
|
||||
// must not receive our credentials.
|
||||
client = &http.Client{
|
||||
Timeout: timeout,
|
||||
Timeout: timeout,
|
||||
Transport: transport,
|
||||
CheckRedirect: func(req *http.Request, via []*http.Request) error {
|
||||
req.Header.Del("Authorization")
|
||||
return nil
|
||||
},
|
||||
}
|
||||
} else {
|
||||
client = &http.Client{Timeout: timeout}
|
||||
client = &http.Client{Timeout: timeout, Transport: transport}
|
||||
}
|
||||
|
||||
resp, err := client.Do(req)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user