Skip to content

Commit 05a9dfd

Browse files
authored
feat: allow configuration of underlying http.Server (#199)
Fixes #194, which pointed out that we should allow configuring additional relevant options on the underlying [http.Server](https://pkg.go.dev/net/http#Server) without requiring users to build and push their own images.
1 parent 3cdcb35 commit 05a9dfd

File tree

3 files changed

+285
-269
lines changed

3 files changed

+285
-269
lines changed

README.md

+4-1
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ variables (or a combination of the two):
9292
| Argument| Env var | Documentation | Default |
9393
| - | - | - | - |
9494
| `-allowed-redirect-domains` | `ALLOWED_REDIRECT_DOMAINS` | Comma-separated list of domains the /redirect-to endpoint will allow | |
95+
| `-exclude-headers` | `EXCLUDE_HEADERS` | Drop platform-specific headers. Comma-separated list of headers key to drop, supporting wildcard suffix matching. For example: `"foo,bar,x-fc-*"` | - |
9596
| `-host` | `HOST` | Host to listen on | "0.0.0.0" |
9697
| `-https-cert-file` | `HTTPS_CERT_FILE` | HTTPS Server certificate file | |
9798
| `-https-key-file` | `HTTPS_KEY_FILE` | HTTPS Server private key file | |
@@ -100,8 +101,10 @@ variables (or a combination of the two):
100101
| `-max-duration` | `MAX_DURATION` | Maximum duration a response may take | 10s |
101102
| `-port` | `PORT` | Port to listen on | 8080 |
102103
| `-prefix` | `PREFIX` | Prefix of path to listen on (must start with slash and does not end with slash) | |
104+
| `-srv-max-header-bytes` | `SRV_MAX_HEADER_BYTES` | Value to use for the http.Server's MaxHeaderBytes option | 16384 |
105+
| `-srv-read-header-timeout` | `SRV_READ_HEADER_TIMEOUT` | Value to use for the http.Server's ReadHeaderTimeout option | 1s |
106+
| `-srv-read-timeout` | `SRV_READ_TIMEOUT` | Value to use for the http.Server's ReadTimeout option | 5s |
103107
| `-use-real-hostname` | `USE_REAL_HOSTNAME` | Expose real hostname as reported by os.Hostname() in the /hostname endpoint | false |
104-
| `-exclude-headers` | `EXCLUDE_HEADERS` | Drop platform-specific headers. Comma-separated list of headers key to drop, supporting wildcard suffix matching. For example: `"foo,bar,x-fc-*"` | - |
105108

106109
**Notes:**
107110
- Command line arguments take precedence over environment variables.

httpbin/cmd/cmd.go

+33-7
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,10 @@ const (
2727
defaultLogFormat = "text"
2828
defaultEnvPrefix = "HTTPBIN_ENV_"
2929

30-
// Reasonable defaults for our http server
31-
srvReadTimeout = 5 * time.Second
32-
srvReadHeaderTimeout = 1 * time.Second
33-
srvMaxHeaderBytes = 16 * 1024 // 16kb
30+
// Reasonable defaults for the underlying http.Server
31+
defaultSrvReadTimeout = 5 * time.Second
32+
defaultSrvReadHeaderTimeout = 1 * time.Second
33+
defaultSrvMaxHeaderBytes = 16 * 1024 // 16kb
3434
)
3535

3636
// Main is the main entrypoint for the go-httpbin binary. See loadConfig() for
@@ -96,9 +96,9 @@ func mainImpl(args []string, getEnvVal func(string) string, getEnviron func() []
9696
srv := &http.Server{
9797
Addr: net.JoinHostPort(cfg.ListenHost, strconv.Itoa(cfg.ListenPort)),
9898
Handler: app.Handler(),
99-
MaxHeaderBytes: srvMaxHeaderBytes,
100-
ReadHeaderTimeout: srvReadHeaderTimeout,
101-
ReadTimeout: srvReadTimeout,
99+
MaxHeaderBytes: cfg.SrvMaxHeaderBytes,
100+
ReadHeaderTimeout: cfg.SrvReadHeaderTimeout,
101+
ReadTimeout: cfg.SrvReadTimeout,
102102
}
103103

104104
if err := listenAndServeGracefully(srv, cfg, logger); err != nil {
@@ -124,6 +124,9 @@ type config struct {
124124
TLSCertFile string
125125
TLSKeyFile string
126126
LogFormat string
127+
SrvMaxHeaderBytes int
128+
SrvReadHeaderTimeout time.Duration
129+
SrvReadTimeout time.Duration
127130

128131
// temporary placeholders for arguments that need extra processing
129132
rawAllowedRedirectDomains string
@@ -162,6 +165,9 @@ func loadConfig(args []string, getEnvVal func(string) string, getEnviron func()
162165
fs.StringVar(&cfg.TLSKeyFile, "https-key-file", "", "HTTPS Server private key file")
163166
fs.StringVar(&cfg.ExcludeHeaders, "exclude-headers", "", "Drop platform-specific headers. Comma-separated list of headers key to drop, supporting wildcard matching.")
164167
fs.StringVar(&cfg.LogFormat, "log-format", defaultLogFormat, "Log format (text or json)")
168+
fs.IntVar(&cfg.SrvMaxHeaderBytes, "srv-max-header-bytes", defaultSrvMaxHeaderBytes, "Value to use for the http.Server's MaxHeaderBytes option")
169+
fs.DurationVar(&cfg.SrvReadHeaderTimeout, "srv-read-header-timeout", defaultSrvReadHeaderTimeout, "Value to use for the http.Server's ReadHeaderTimeout option")
170+
fs.DurationVar(&cfg.SrvReadTimeout, "srv-read-timeout", defaultSrvReadTimeout, "Value to use for the http.Server's ReadTimeout option")
165171

166172
// in order to fully control error output whether CLI arguments or env vars
167173
// are used to configure the app, we need to take control away from the
@@ -275,6 +281,26 @@ func loadConfig(args []string, getEnvVal func(string) string, getEnviron func()
275281
}
276282
}
277283

284+
// set the http.Server options
285+
if cfg.SrvMaxHeaderBytes == defaultSrvMaxHeaderBytes && getEnvVal("SRV_MAX_HEADER_BYTES") != "" {
286+
cfg.SrvMaxHeaderBytes, err = strconv.Atoi(getEnvVal("SRV_MAX_HEADER_BYTES"))
287+
if err != nil {
288+
return nil, configErr("invalid value %#v for env var SRV_MAX_HEADER_BYTES: parse error", getEnvVal("SRV_MAX_HEADER_BYTES"))
289+
}
290+
}
291+
if cfg.SrvReadHeaderTimeout == defaultSrvReadHeaderTimeout && getEnvVal("SRV_READ_HEADER_TIMEOUT") != "" {
292+
cfg.SrvReadHeaderTimeout, err = time.ParseDuration(getEnvVal("SRV_READ_HEADER_TIMEOUT"))
293+
if err != nil {
294+
return nil, configErr("invalid value %#v for env var SRV_READ_HEADER_TIMEOUT: parse error", getEnvVal("SRV_READ_HEADER_TIMEOUT"))
295+
}
296+
}
297+
if cfg.SrvReadTimeout == defaultSrvReadTimeout && getEnvVal("SRV_READ_TIMEOUT") != "" {
298+
cfg.SrvReadTimeout, err = time.ParseDuration(getEnvVal("SRV_READ_TIMEOUT"))
299+
if err != nil {
300+
return nil, configErr("invalid value %#v for env var SRV_READ_TIMEOUT: parse error", getEnvVal("SRV_READ_TIMEOUT"))
301+
}
302+
}
303+
278304
// reset temporary fields to their zero values
279305
cfg.rawAllowedRedirectDomains = ""
280306
cfg.rawUseRealHostname = false

0 commit comments

Comments
 (0)