Skip to content

-read_timeout 0 does not disable the read timeout; only a negative value works (contradicts flag help) #50

Description

@Robbie1977

Summary

The -read_timeout flag help states "zero or negative value means no timeout", but passing 0 does not disable the timeout — the built-in 15s default is applied instead. Only a negative value (e.g. -1s) actually disables it. -write_timeout is unaffected only because its default is already 0.

Environment

  • Version: v2 (branch v2), reproduced with the mayth/simple-upload-server image
  • Docker, Linux

Expected

Per the flag help, -read_timeout 0 should disable the read timeout (map to http.Server.ReadTimeout = 0, which Go treats as no timeout), consistent with -write_timeout 0.

Actual

0 is treated as "unset" and replaced by the 15s default. Startup logs:

# no -read_timeout flag
config from flag:   ReadTimeout:0
merged flag config: ReadTimeout:15000000000
configured:         ReadTimeout:15s

# -read_timeout=0  (explicit) -> still 15s

# -read_timeout=-1s
configured:         ReadTimeout:-1s        # works: no timeout

Consequence: any upload whose body transfer exceeds 15s is cut mid-stream — the handler's r.FormFile read fails with failed to obtain form file: ... i/o timeout and returns 500 — making large uploads (multi-GB over ordinary links) impossible unless the operator discovers the undocumented -1s workaround.

Root cause

In app.go, ParseConfig builds configFromFlags and merges it over DefaultConfig:

config := DefaultConfig            // ReadTimeout: Duration(15 * time.Second)
configFromFlags := ServerConfig{ /* ... */ ReadTimeout: Duration(a.readTimeout) }
mergo.Merge(&config, configFromFlags, mergo.WithOverride)

mergo.Merge with WithOverride does not override a destination field when the source field is a zero value. An explicit -read_timeout 0 parses to a.readTimeout == 0, which is indistinguishable from the flag being unset, so mergo skips it and the 15s DefaultConfig.ReadTimeout stands. Only a non-zero (negative) duration overrides.

Proposed fix

Distinguish "flag not provided" from "explicitly set" for the timeout flags — e.g. re-apply them after the merge via flag.Visit — so -read_timeout 0 maps to ReadTimeout: 0 (no timeout) as documented. This mirrors the existing IsSet() handling used for the bool flags. PR to follow.

Workaround

-read_timeout=-1s (any negative duration).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions