Skip to content

Commit

Permalink
http timeout values are configurable (#6666)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
lexman42 authored and briankassouf committed Jun 4, 2019
1 parent 5dd4ce2 commit e60a216
Show file tree
Hide file tree
Showing 3 changed files with 140 additions and 8 deletions.
56 changes: 56 additions & 0 deletions command/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ type ServerCommand struct {
flagDevAutoSeal bool
flagTestVerifyOnly bool
flagCombineLogs bool
flagTestServerConfig bool
}

type ServerListener struct {
Expand Down Expand Up @@ -305,6 +306,13 @@ func (c *ServerCommand) Flags() *FlagSets {
Hidden: true,
})

f.BoolVar(&BoolVar{
Name: "test-server-config",
Target: &c.flagTestServerConfig,
Default: false,
Hidden: true,
})

// End internal-only flags.

return set
Expand Down Expand Up @@ -1146,16 +1154,64 @@ CLUSTER_SYNTHESIS_COMPLETE:
}
}

// server defaults
server := &http.Server{
Handler: handler,
ReadHeaderTimeout: 10 * time.Second,
ReadTimeout: 30 * time.Second,
IdleTimeout: 5 * time.Minute,
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)
}

if c.flagTestServerConfig {
return 0
}

if sealConfigError != nil {
init, err := core.Initialized(context.Background())
if err != nil {
Expand Down
73 changes: 65 additions & 8 deletions command/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,19 +41,30 @@ func testRandomPort(tb testing.TB) int {
return l.Addr().(*net.TCPAddr).Port
}

func testBaseHCL(tb testing.TB) string {
func testBaseHCL(tb testing.TB, listenerExtras string) string {
tb.Helper()

return strings.TrimSpace(fmt.Sprintf(`
disable_mlock = true
listener "tcp" {
address = "127.0.0.1:%d"
tls_disable = "true"
address = "127.0.0.1:%d"
tls_disable = "true"
%s
}
`, testRandomPort(tb)))
`, testRandomPort(tb), listenerExtras))
}

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 = `
backend "inmem_ha" {
advertise_addr = "http://127.0.0.1:8200"
Expand Down Expand Up @@ -204,24 +215,70 @@ func TestServer(t *testing.T) {
contents string
exp string
code int
flag string
}{
{
"common_ha",
testBaseHCL(t) + inmemHCL,
testBaseHCL(t, "") + inmemHCL,
"(HA available)",
0,
"-test-verify-only",
},
{
"separate_ha",
testBaseHCL(t) + inmemHCL + haInmemHCL,
testBaseHCL(t, "") + inmemHCL + haInmemHCL,
"HA Storage:",
0,
"-test-verify-only",
},
{
"bad_separate_ha",
testBaseHCL(t) + inmemHCL + badHAInmemHCL,
testBaseHCL(t, "") + inmemHCL + badHAInmemHCL,
"Specified HA storage does not support HA",
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",
},
}

Expand All @@ -242,7 +299,7 @@ func TestServer(t *testing.T) {

code := cmd.Run([]string{
"-config", f.Name(),
"-test-verify-only",
tc.flag,
})
output := ui.ErrorWriter.String() + ui.OutputWriter.String()
if code != tc.code {
Expand Down
19 changes: 19 additions & 0 deletions website/source/docs/configuration/listener/tcp.html.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
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
request size, in bytes. Defaults to 32 MB. Specifying a number less than or
equal to `0` turns off limiting altogether.
Expand Down

0 comments on commit e60a216

Please sign in to comment.