Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ The following emojis are used to highlight certain changes:

### Added

- `gateway`: Added a configurable fallback timeout for the gateway handler, defaulting to 1 hour, overridable via the BOXO_GATEWAY_REQUEST_TIMEOUT environment variable.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@acejam The existing gateway configuration uses a boxo/gateway/Config struct with explicit fields (e.g., RetrievalTimeout, MaxConcurrentRequests). Using an environment variable is inconsistent with the established pattern and we can't merge this in this form.

Consider adding MaxRequestDuration to the Config struct instead? This would be consistent with how other timeouts are configured and allows programmatic

- `routing/http`: `GET /routing/v1/dht/closest/peers/{key}` per [IPIP-476](https://github.com/ipfs/specs/pull/476)

### Changed
Expand Down
18 changes: 17 additions & 1 deletion gateway/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"net/http"
"net/textproto"
"net/url"
"os"
gopath "path"
"regexp"
"runtime/debug"
Expand Down Expand Up @@ -42,6 +43,21 @@ var (
noModtime = time.Unix(0, 0) // disables Last-Modified header if passed as modtime
)

// fallbackRequestTimeout defines the hard per-request timeout for the gateway handler.
// It defaults to 1h, but can be overridden via the BOXO_GATEWAY_REQUEST_TIMEOUT env var,
// which accepts Go duration strings (e.g., "90m", "2h", "5400s").
var fallbackRequestTimeout = time.Hour

func init() {
if v := os.Getenv("BOXO_GATEWAY_REQUEST_TIMEOUT"); v != "" {
if d, err := time.ParseDuration(v); err == nil && d > 0 {
fallbackRequestTimeout = d
} else {
log.Warnw("invalid BOXO_GATEWAY_REQUEST_TIMEOUT, using default 1h", "value", v, "error", err)
}
}
}

// handler is a HTTP handler that serves IPFS objects (accessible by default at /ipfs/<path>)
// (it serves requests like GET /ipfs/QmVRzPKPzNtSrEzBFm2UZfxmPAgnaLke4DMcerbsGGSaFe/link)
type handler struct {
Expand Down Expand Up @@ -159,7 +175,7 @@ func (i *handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
defer panicHandler(w)

// the hour is a hard fallback, we don't expect it to happen, but just in case
ctx, cancel := context.WithTimeout(r.Context(), time.Hour)
ctx, cancel := context.WithTimeout(r.Context(), fallbackRequestTimeout)
defer cancel()

if withCtxWrap, ok := i.backend.(WithContextHint); ok {
Expand Down
Loading