http timeout values are configurable (#6666)

* http timeout fields are configurable

* move return statement for server config tests outside of range loop

* adds documentation for configurable listener http_* values

* fixed some formatting for the docs markdown
This commit is contained in:
Lexman 2019-05-10 10:41:42 -07:00 committed by GitHub
parent 155aa5de9d
commit b2850ac624
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 140 additions and 8 deletions

View File

@ -106,6 +106,7 @@ type ServerCommand struct {
flagDevAutoSeal bool flagDevAutoSeal bool
flagTestVerifyOnly bool flagTestVerifyOnly bool
flagCombineLogs bool flagCombineLogs bool
flagTestServerConfig bool
} }
type ServerListener struct { type ServerListener struct {
@ -305,6 +306,13 @@ func (c *ServerCommand) Flags() *FlagSets {
Hidden: true, Hidden: true,
}) })
f.BoolVar(&BoolVar{
Name: "test-server-config",
Target: &c.flagTestServerConfig,
Default: false,
Hidden: true,
})
// End internal-only flags. // End internal-only flags.
return set return set
@ -1146,6 +1154,7 @@ CLUSTER_SYNTHESIS_COMPLETE:
} }
} }
// server defaults
server := &http.Server{ server := &http.Server{
Handler: handler, Handler: handler,
ReadHeaderTimeout: 10 * time.Second, ReadHeaderTimeout: 10 * time.Second,
@ -1153,9 +1162,56 @@ CLUSTER_SYNTHESIS_COMPLETE:
IdleTimeout: 5 * time.Minute, IdleTimeout: 5 * time.Minute,
ErrorLog: c.logger.StandardLogger(nil), ErrorLog: c.logger.StandardLogger(nil),
} }
// override server defaults with config values for read/write/idle timeouts if configured
if readHeaderTimeoutInterface, ok := ln.config["http_read_header_timeout"]; ok {
readHeaderTimeout, err := parseutil.ParseDurationSecond(readHeaderTimeoutInterface)
if err != nil {
c.UI.Error(fmt.Sprintf("Could not parse a time value for http_read_header_timeout %v", readHeaderTimeout))
return 1
}
server.ReadHeaderTimeout = readHeaderTimeout
}
if readTimeoutInterface, ok := ln.config["http_read_timeout"]; ok {
readTimeout, err := parseutil.ParseDurationSecond(readTimeoutInterface)
if err != nil {
c.UI.Error(fmt.Sprintf("Could not parse a time value for http_read_timeout %v", readTimeout))
return 1
}
server.ReadTimeout = readTimeout
}
if writeTimeoutInterface, ok := ln.config["http_write_timeout"]; ok {
writeTimeout, err := parseutil.ParseDurationSecond(writeTimeoutInterface)
if err != nil {
c.UI.Error(fmt.Sprintf("Could not parse a time value for http_write_timeout %v", writeTimeout))
return 1
}
server.WriteTimeout = writeTimeout
}
if idleTimeoutInterface, ok := ln.config["http_idle_timeout"]; ok {
idleTimeout, err := parseutil.ParseDurationSecond(idleTimeoutInterface)
if err != nil {
c.UI.Error(fmt.Sprintf("Could not parse a time value for http_idle_timeout %v", idleTimeout))
return 1
}
server.IdleTimeout = idleTimeout
}
// server config tests can exit now
if c.flagTestServerConfig {
continue
}
go server.Serve(ln.Listener) go server.Serve(ln.Listener)
} }
if c.flagTestServerConfig {
return 0
}
if sealConfigError != nil { if sealConfigError != nil {
init, err := core.Initialized(context.Background()) init, err := core.Initialized(context.Background())
if err != nil { if err != nil {

View File

@ -41,7 +41,7 @@ func testRandomPort(tb testing.TB) int {
return l.Addr().(*net.TCPAddr).Port return l.Addr().(*net.TCPAddr).Port
} }
func testBaseHCL(tb testing.TB) string { func testBaseHCL(tb testing.TB, listenerExtras string) string {
tb.Helper() tb.Helper()
return strings.TrimSpace(fmt.Sprintf(` return strings.TrimSpace(fmt.Sprintf(`
@ -49,11 +49,22 @@ func testBaseHCL(tb testing.TB) string {
listener "tcp" { listener "tcp" {
address = "127.0.0.1:%d" address = "127.0.0.1:%d"
tls_disable = "true" tls_disable = "true"
%s
} }
`, testRandomPort(tb))) `, testRandomPort(tb), listenerExtras))
} }
const ( const (
goodListenerTimeouts = `http_read_header_timeout = 12
http_read_timeout = "34s"
http_write_timeout = "56m"
http_idle_timeout = "78h"`
badListenerReadHeaderTimeout = `http_read_header_timeout = "12km"`
badListenerReadTimeout = `http_read_timeout = "34日"`
badListenerWriteTimeout = `http_write_timeout = "56lbs"`
badListenerIdleTimeout = `http_idle_timeout = "78gophers"`
inmemHCL = ` inmemHCL = `
backend "inmem_ha" { backend "inmem_ha" {
advertise_addr = "http://127.0.0.1:8200" advertise_addr = "http://127.0.0.1:8200"
@ -204,24 +215,70 @@ func TestServer(t *testing.T) {
contents string contents string
exp string exp string
code int code int
flag string
}{ }{
{ {
"common_ha", "common_ha",
testBaseHCL(t) + inmemHCL, testBaseHCL(t, "") + inmemHCL,
"(HA available)", "(HA available)",
0, 0,
"-test-verify-only",
}, },
{ {
"separate_ha", "separate_ha",
testBaseHCL(t) + inmemHCL + haInmemHCL, testBaseHCL(t, "") + inmemHCL + haInmemHCL,
"HA Storage:", "HA Storage:",
0, 0,
"-test-verify-only",
}, },
{ {
"bad_separate_ha", "bad_separate_ha",
testBaseHCL(t) + inmemHCL + badHAInmemHCL, testBaseHCL(t, "") + inmemHCL + badHAInmemHCL,
"Specified HA storage does not support HA", "Specified HA storage does not support HA",
1, 1,
"-test-verify-only",
},
{
"good_listener_timeout_config",
testBaseHCL(t, goodListenerTimeouts) + inmemHCL,
"",
0,
"-test-server-config",
},
{
"bad_listener_read_header_timeout_config",
testBaseHCL(t, badListenerReadHeaderTimeout) + inmemHCL,
"Could not parse a time value for http_read_header_timeout",
1,
"-test-server-config",
},
{
"bad_listener_read_header_timeout_config",
testBaseHCL(t, badListenerReadHeaderTimeout) + inmemHCL,
"Could not parse a time value for http_read_header_timeout",
1,
"-test-server-config",
},
{
"bad_listener_read_timeout_config",
testBaseHCL(t, badListenerReadTimeout) + inmemHCL,
"Could not parse a time value for http_read_timeout",
1,
"-test-server-config",
},
{
"bad_listener_write_timeout_config",
testBaseHCL(t, badListenerWriteTimeout) + inmemHCL,
"Could not parse a time value for http_write_timeout",
1,
"-test-server-config",
},
{
"bad_listener_idle_timeout_config",
testBaseHCL(t, badListenerIdleTimeout) + inmemHCL,
"Could not parse a time value for http_idle_timeout",
1,
"-test-server-config",
}, },
} }
@ -242,7 +299,7 @@ func TestServer(t *testing.T) {
code := cmd.Run([]string{ code := cmd.Run([]string{
"-config", f.Name(), "-config", f.Name(),
"-test-verify-only", tc.flag,
}) })
output := ui.ErrorWriter.String() + ui.OutputWriter.String() output := ui.ErrorWriter.String() + ui.OutputWriter.String()
if code != tc.code { if code != tc.code {

View File

@ -35,6 +35,25 @@ advertise the correct address to other nodes.
they need to hop through a TCP load balancer or some other scheme in order to they need to hop through a TCP load balancer or some other scheme in order to
talk. talk.
- `http_idle_timeout` `(string: "5m")` - Specifies the maximum amount of time to
wait for the next request when keep-alives are enabled. If `http_idle_timeout`
is zero, the value of `http_read_timeout` is used. If both are zero, the value
of `http_read_header_timeout` is used. This is specified using a label suffix
like `"30s"` or `"1h"`.
- `http_read_header_timeout` `(string: "10s")` - Specifies the amount of time
allowed to read request headers. This is specified using a label suffix like
`"30s"` or `"1h"`.
- `http_read_timeout` `(string: "30s")` - Specifies the maximum duration for
reading the entire request, including the body. This is specified using a
label suffix like `"30s"` or `"1h"`.
- `http_write_timeout` `string: "0")` - Specifies the maximum duration before
timing out writes of the response and is reset whenever a new request's header
is read. The default value of `"0"` means inifinity. This is specified using a
label suffix like `"30s"` or `"1h"`.
- `max_request_size` `(int: 33554432)` Specifies a hard maximum allowed - `max_request_size` `(int: 33554432)` Specifies a hard maximum allowed
request size, in bytes. Defaults to 32 MB. Specifying a number less than or request size, in bytes. Defaults to 32 MB. Specifying a number less than or
equal to `0` turns off limiting altogether. equal to `0` turns off limiting altogether.