1// Package httpclient centralizes HTTP timeout defaults so the rest of the
2// codebase doesn't sprinkle magic numbers across packages.
3package httpclient
4
5import (
6 "fmt"
7 "net/http"
8 "time"
9)
10
11// Named timeouts. Each constant documents the call site it covers so
12// future contributors don't have to grep for callers.
13const (
14 // PluginCallTimeout bounds Lua-driven plugin HTTP calls (plugin/http.go).
15 PluginCallTimeout = 10 * time.Second
16 // RegistryFetchTimeout bounds plugin registry / plugin file fetches (plugins/embed.go).
17 RegistryFetchTimeout = 10 * time.Second
18 // RemoteImageTimeout bounds inline image fetches (view/html.go).
19 // Kept short so message rendering doesn't stall.
20 RemoteImageTimeout = 5 * time.Second
21 // InstallTimeout bounds CLI install downloads (cli/install.go).
22 InstallTimeout = 30 * time.Second
23 // UpdateCheckTimeout bounds version checks and asset downloads from main (main.go).
24 UpdateCheckTimeout = 30 * time.Second
25)
26
27// New returns an http.Client preconfigured with the given timeout.
28func New(timeout time.Duration) *http.Client {
29 return &http.Client{Timeout: timeout}
30}
31
32// NewWithRedirectCap returns an http.Client with the given timeout and a
33// hard cap on the number of redirects it will follow before giving up.
34// Used by the main update / asset download client to avoid infinite chains.
35func NewWithRedirectCap(timeout time.Duration, maxRedirects int) *http.Client {
36 return &http.Client{
37 Timeout: timeout,
38 CheckRedirect: func(req *http.Request, via []*http.Request) error {
39 if len(via) >= maxRedirects {
40 return fmt.Errorf("stopped after %d redirects", maxRedirects)
41 }
42 return nil
43 },
44 }
45}