diff --git a/cmd/XDC/main.go b/cmd/XDC/main.go index a241614d87..7169f1decd 100644 --- a/cmd/XDC/main.go +++ b/cmd/XDC/main.go @@ -147,6 +147,7 @@ var ( utils.HTTPListenAddrFlag, utils.HTTPPortFlag, utils.HTTPReadTimeoutFlag, + utils.HTTPReadHeaderTimeoutFlag, utils.HTTPWriteTimeoutFlag, utils.HTTPIdleTimeoutFlag, utils.HTTPApiFlag, diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index ce9c730226..97b2490270 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -476,6 +476,12 @@ var ( Value: rpc.DefaultHTTPTimeouts.ReadTimeout, Category: flags.APICategory, } + HTTPReadHeaderTimeoutFlag = &cli.DurationFlag{ + Name: "http-readheadertimeout", + Usage: "HTTP-RPC server read timeout", + Value: rpc.DefaultHTTPTimeouts.ReadHeaderTimeout, + Category: flags.APICategory, + } HTTPWriteTimeoutFlag = &cli.DurationFlag{ Name: "http-writetimeout", Aliases: []string{"rpcwritetimeout"}, @@ -999,6 +1005,9 @@ func setHTTP(ctx *cli.Context, cfg *node.Config) { if ctx.IsSet(HTTPReadTimeoutFlag.Name) { cfg.HTTPTimeouts.ReadTimeout = ctx.Duration(HTTPReadTimeoutFlag.Name) } + if ctx.IsSet(HTTPReadHeaderTimeoutFlag.Name) { + cfg.HTTPTimeouts.ReadHeaderTimeout = ctx.Duration(HTTPReadHeaderTimeoutFlag.Name) + } if ctx.IsSet(HTTPWriteTimeoutFlag.Name) { cfg.HTTPTimeouts.WriteTimeout = ctx.Duration(HTTPWriteTimeoutFlag.Name) } diff --git a/node/endpoints.go b/node/endpoints.go index 312d925567..a6a7318759 100644 --- a/node/endpoints.go +++ b/node/endpoints.go @@ -48,6 +48,10 @@ func CheckTimeouts(timeouts *rpc.HTTPTimeouts) { log.Warn("Sanitizing invalid HTTP read timeout", "provided", timeouts.ReadTimeout, "updated", rpc.DefaultHTTPTimeouts.ReadTimeout) timeouts.ReadTimeout = rpc.DefaultHTTPTimeouts.ReadTimeout } + if timeouts.ReadHeaderTimeout < time.Second { + log.Warn("Sanitizing invalid HTTP read header timeout", "provided", timeouts.ReadHeaderTimeout, "updated", rpc.DefaultHTTPTimeouts.ReadHeaderTimeout) + timeouts.ReadHeaderTimeout = rpc.DefaultHTTPTimeouts.ReadHeaderTimeout + } if timeouts.WriteTimeout < 2*time.Second { log.Warn("Sanitizing invalid HTTP write timeout", "provided", timeouts.WriteTimeout, "updated", rpc.DefaultHTTPTimeouts.WriteTimeout) timeouts.WriteTimeout = rpc.DefaultHTTPTimeouts.WriteTimeout diff --git a/node/rpcstack.go b/node/rpcstack.go index fd9d00a6ea..829c0b77bf 100644 --- a/node/rpcstack.go +++ b/node/rpcstack.go @@ -125,10 +125,11 @@ func (h *httpServer) start() error { h.server = &http.Server{Handler: h} if h.timeouts != (rpc.HTTPTimeouts{}) { h.server.ReadTimeout = h.timeouts.ReadTimeout + h.server.ReadHeaderTimeout = h.timeouts.ReadHeaderTimeout h.server.WriteTimeout = h.timeouts.WriteTimeout h.server.IdleTimeout = h.timeouts.IdleTimeout } - log.Info("Start http server", "ReadTimeout", h.server.ReadTimeout, "WriteTimeout", h.server.WriteTimeout, "IdleTimeout", h.server.IdleTimeout) + log.Info("Start http server", "ReadTimeout", h.server.ReadTimeout, "ReadHeaderTimeout", h.server.ReadHeaderTimeout, "WriteTimeout", h.server.WriteTimeout, "IdleTimeout", h.server.IdleTimeout) // Start the server. listener, err := net.Listen("tcp", h.endpoint) if err != nil { diff --git a/rpc/http.go b/rpc/http.go index 45da82dff8..403a7a73b2 100644 --- a/rpc/http.go +++ b/rpc/http.go @@ -87,6 +87,14 @@ type HTTPTimeouts struct { // ReadHeaderTimeout. It is valid to use them both. ReadTimeout time.Duration + // ReadHeaderTimeout is the amount of time allowed to read + // request headers. The connection's read deadline is reset + // after reading the headers and the Handler can decide what + // is considered too slow for the body. If ReadHeaderTimeout + // is zero, the value of ReadTimeout is used. If both are + // zero, there is no timeout. + ReadHeaderTimeout time.Duration + // WriteTimeout is the maximum duration before timing out // writes of the response. It is reset whenever a new // request's header is read. Like ReadTimeout, it does not @@ -103,9 +111,10 @@ type HTTPTimeouts struct { // DefaultHTTPTimeouts represents the default timeout values used if further // configuration is not provided. var DefaultHTTPTimeouts = HTTPTimeouts{ - ReadTimeout: 30 * time.Second, - WriteTimeout: 30 * time.Second, - IdleTimeout: 120 * time.Second, + ReadTimeout: 30 * time.Second, + ReadHeaderTimeout: 30 * time.Second, + WriteTimeout: 30 * time.Second, + IdleTimeout: 120 * time.Second, } // DialHTTPWithClient creates a new RPC client that connects to an RPC server over HTTP