Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

http timeout values are configurable #6666

Merged
6 commits merged into from
May 10, 2019
Merged
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
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