mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-19 21:31:37 +00:00
rpc: Make HTTP server timeout values configurable (#17240)
This commit is contained in:
parent
56bce3983d
commit
97a5ff616b
9 changed files with 64 additions and 27 deletions
|
|
@ -147,7 +147,9 @@ var (
|
|||
utils.RPCGlobalGasCapFlag,
|
||||
utils.RPCListenAddrFlag,
|
||||
utils.RPCPortFlag,
|
||||
utils.RPCHttpReadTimeoutFlag,
|
||||
utils.RPCHttpWriteTimeoutFlag,
|
||||
utils.RPCHttpIdleTimeoutFlag,
|
||||
utils.RPCApiFlag,
|
||||
utils.WSEnabledFlag,
|
||||
utils.WSListenAddrFlag,
|
||||
|
|
|
|||
|
|
@ -147,7 +147,9 @@ var AppHelpFlagGroups = []flagGroup{
|
|||
utils.RPCGlobalGasCapFlag,
|
||||
utils.RPCListenAddrFlag,
|
||||
utils.RPCPortFlag,
|
||||
utils.RPCHttpReadTimeoutFlag,
|
||||
utils.RPCHttpWriteTimeoutFlag,
|
||||
utils.RPCHttpIdleTimeoutFlag,
|
||||
utils.RPCApiFlag,
|
||||
utils.WSEnabledFlag,
|
||||
utils.WSListenAddrFlag,
|
||||
|
|
|
|||
|
|
@ -435,10 +435,20 @@ var (
|
|||
Usage: "HTTP-RPC server listening port",
|
||||
Value: node.DefaultHTTPPort,
|
||||
}
|
||||
RPCHttpReadTimeoutFlag = cli.DurationFlag{
|
||||
Name: "rpcreadtimeout",
|
||||
Usage: "HTTP-RPC server read timeout",
|
||||
Value: rpc.DefaultHTTPTimeouts.ReadTimeout,
|
||||
}
|
||||
RPCHttpWriteTimeoutFlag = cli.DurationFlag{
|
||||
Name: "rpcwritetimeout",
|
||||
Usage: "HTTP-RPC server write timeout (default = 10s)",
|
||||
Value: node.DefaultHTTPWriteTimeOut,
|
||||
Usage: "HTTP-RPC server write timeout",
|
||||
Value: rpc.DefaultHTTPTimeouts.WriteTimeout,
|
||||
}
|
||||
RPCHttpIdleTimeoutFlag = cli.DurationFlag{
|
||||
Name: "rpcidletimeout",
|
||||
Usage: "HTTP-RPC server idle timeout",
|
||||
Value: rpc.DefaultHTTPTimeouts.IdleTimeout,
|
||||
}
|
||||
RPCCORSDomainFlag = cli.StringFlag{
|
||||
Name: "rpccorsdomain",
|
||||
|
|
@ -779,8 +789,14 @@ func setHTTP(ctx *cli.Context, cfg *node.Config) {
|
|||
if ctx.GlobalIsSet(RPCPortFlag.Name) {
|
||||
cfg.HTTPPort = ctx.GlobalInt(RPCPortFlag.Name)
|
||||
}
|
||||
if ctx.GlobalIsSet(RPCHttpReadTimeoutFlag.Name) {
|
||||
cfg.HTTPTimeouts.ReadTimeout = ctx.GlobalDuration(RPCHttpReadTimeoutFlag.Name)
|
||||
}
|
||||
if ctx.GlobalIsSet(RPCHttpWriteTimeoutFlag.Name) {
|
||||
cfg.HTTPWriteTimeout = ctx.GlobalDuration(RPCHttpWriteTimeoutFlag.Name)
|
||||
cfg.HTTPTimeouts.WriteTimeout = ctx.GlobalDuration(RPCHttpWriteTimeoutFlag.Name)
|
||||
}
|
||||
if ctx.GlobalIsSet(RPCHttpIdleTimeoutFlag.Name) {
|
||||
cfg.HTTPTimeouts.IdleTimeout = ctx.GlobalDuration(RPCHttpIdleTimeoutFlag.Name)
|
||||
}
|
||||
if ctx.GlobalIsSet(RPCCORSDomainFlag.Name) {
|
||||
cfg.HTTPCors = splitAndTrim(ctx.GlobalString(RPCCORSDomainFlag.Name))
|
||||
|
|
|
|||
|
|
@ -158,7 +158,7 @@ func (api *PrivateAdminAPI) StartRPC(host *string, port *int, cors *string, apis
|
|||
}
|
||||
}
|
||||
|
||||
if err := api.node.startHTTP(fmt.Sprintf("%s:%d", *host, *port), api.node.rpcAPIs, modules, allowedOrigins, allowedVHosts); err != nil {
|
||||
if err := api.node.startHTTP(fmt.Sprintf("%s:%d", *host, *port), api.node.rpcAPIs, modules, allowedOrigins, allowedVHosts, api.node.config.HTTPTimeouts); err != nil {
|
||||
return false, err
|
||||
}
|
||||
return true, nil
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ import (
|
|||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/XinFinOrg/XDPoSChain/accounts"
|
||||
"github.com/XinFinOrg/XDPoSChain/accounts/keystore"
|
||||
|
|
@ -33,6 +32,7 @@ import (
|
|||
"github.com/XinFinOrg/XDPoSChain/log"
|
||||
"github.com/XinFinOrg/XDPoSChain/p2p"
|
||||
"github.com/XinFinOrg/XDPoSChain/p2p/discover"
|
||||
"github.com/XinFinOrg/XDPoSChain/rpc"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
@ -100,9 +100,6 @@ type Config struct {
|
|||
// for ephemeral nodes).
|
||||
HTTPPort int `toml:",omitempty"`
|
||||
|
||||
// HTTPWriteTimeout is the write timeout for the HTTP RPC server.
|
||||
HTTPWriteTimeout time.Duration `toml:",omitempty"`
|
||||
|
||||
// HTTPCors is the Cross-Origin Resource Sharing header to send to requesting
|
||||
// clients. Please be aware that CORS is a browser enforced security, it's fully
|
||||
// useless for custom HTTP clients.
|
||||
|
|
@ -122,6 +119,10 @@ type Config struct {
|
|||
// exposed.
|
||||
HTTPModules []string `toml:",omitempty"`
|
||||
|
||||
// HTTPTimeouts allows for customization of the timeout values used by the HTTP RPC
|
||||
// interface.
|
||||
HTTPTimeouts rpc.HTTPTimeouts
|
||||
|
||||
// WSHost is the host interface on which to start the websocket RPC server. If
|
||||
// this field is empty, no websocket API endpoint will be started.
|
||||
WSHost string `toml:",omitempty"`
|
||||
|
|
|
|||
|
|
@ -21,27 +21,26 @@ import (
|
|||
"os/user"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"time"
|
||||
|
||||
"github.com/XinFinOrg/XDPoSChain/p2p"
|
||||
"github.com/XinFinOrg/XDPoSChain/p2p/nat"
|
||||
"github.com/XinFinOrg/XDPoSChain/rpc"
|
||||
)
|
||||
|
||||
const (
|
||||
DefaultHTTPHost = "localhost" // Default host interface for the HTTP RPC server
|
||||
DefaultHTTPPort = 8545 // Default TCP port for the HTTP RPC server
|
||||
DefaultHTTPWriteTimeOut = 10 * time.Second // Default write timeout for the HTTP RPC server
|
||||
DefaultWSHost = "localhost" // Default host interface for the websocket RPC server
|
||||
DefaultWSPort = 8546 // Default TCP port for the websocket RPC server
|
||||
DefaultHTTPHost = "localhost" // Default host interface for the HTTP RPC server
|
||||
DefaultHTTPPort = 8545 // Default TCP port for the HTTP RPC server
|
||||
DefaultWSHost = "localhost" // Default host interface for the websocket RPC server
|
||||
DefaultWSPort = 8546 // Default TCP port for the websocket RPC server
|
||||
)
|
||||
|
||||
// DefaultConfig contains reasonable default settings.
|
||||
var DefaultConfig = Config{
|
||||
DataDir: DefaultDataDir(),
|
||||
HTTPPort: DefaultHTTPPort,
|
||||
HTTPWriteTimeout: DefaultHTTPWriteTimeOut,
|
||||
HTTPModules: []string{"net", "web3"},
|
||||
HTTPVirtualHosts: []string{"localhost"},
|
||||
HTTPTimeouts: rpc.DefaultHTTPTimeouts,
|
||||
WSPort: DefaultWSPort,
|
||||
WSModules: []string{"net", "web3"},
|
||||
P2P: p2p.Config{
|
||||
|
|
|
|||
|
|
@ -269,7 +269,7 @@ func (n *Node) startRPC(services map[reflect.Type]Service) error {
|
|||
n.stopInProc()
|
||||
return err
|
||||
}
|
||||
if err := n.startHTTP(n.httpEndpoint, apis, n.config.HTTPModules, n.config.HTTPCors, n.config.HTTPVirtualHosts); err != nil {
|
||||
if err := n.startHTTP(n.httpEndpoint, apis, n.config.HTTPModules, n.config.HTTPCors, n.config.HTTPVirtualHosts, n.config.HTTPTimeouts); err != nil {
|
||||
n.stopIPC()
|
||||
n.stopInProc()
|
||||
return err
|
||||
|
|
@ -348,12 +348,12 @@ func (n *Node) stopIPC() {
|
|||
}
|
||||
|
||||
// startHTTP initializes and starts the HTTP RPC endpoint.
|
||||
func (n *Node) startHTTP(endpoint string, apis []rpc.API, modules []string, cors []string, vhosts []string) error {
|
||||
func (n *Node) startHTTP(endpoint string, apis []rpc.API, modules []string, cors []string, vhosts []string, timeouts rpc.HTTPTimeouts) error {
|
||||
// Short circuit if the HTTP endpoint isn't being exposed
|
||||
if endpoint == "" {
|
||||
return nil
|
||||
}
|
||||
listener, handler, err := rpc.StartHTTPEndpoint(endpoint, apis, modules, cors, vhosts, n.config.HTTPWriteTimeout)
|
||||
listener, handler, err := rpc.StartHTTPEndpoint(endpoint, apis, modules, cors, vhosts, timeouts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,13 +19,12 @@ package rpc
|
|||
import (
|
||||
"net"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/XinFinOrg/XDPoSChain/log"
|
||||
)
|
||||
|
||||
// StartHTTPEndpoint starts the HTTP RPC endpoint, configured with cors/vhosts/modules
|
||||
func StartHTTPEndpoint(endpoint string, apis []API, modules []string, cors []string, vhosts []string, timeout time.Duration) (net.Listener, *Server, error) {
|
||||
func StartHTTPEndpoint(endpoint string, apis []API, modules []string, cors []string, vhosts []string, timeouts HTTPTimeouts) (net.Listener, *Server, error) {
|
||||
// Generate the whitelist based on the allowed modules
|
||||
whitelist := make(map[string]bool)
|
||||
for _, module := range modules {
|
||||
|
|
@ -49,7 +48,7 @@ func StartHTTPEndpoint(endpoint string, apis []API, modules []string, cors []str
|
|||
if listener, err = net.Listen("tcp", endpoint); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
go NewHTTPServer(cors, vhosts, handler, timeout).Serve(listener)
|
||||
go NewHTTPServer(cors, vhosts, timeouts, handler).Serve(listener)
|
||||
return listener, handler, err
|
||||
}
|
||||
|
||||
|
|
|
|||
30
rpc/http.go
30
rpc/http.go
|
|
@ -240,17 +240,35 @@ func (t *httpServerConn) SetWriteDeadline(time.Time) error { return nil }
|
|||
// NewHTTPServer creates a new HTTP RPC server around an API provider.
|
||||
//
|
||||
// Deprecated: Server implements http.Handler
|
||||
func NewHTTPServer(cors []string, vhosts []string, srv *Server, writeTimeout time.Duration) *http.Server {
|
||||
func NewHTTPServer(cors []string, vhosts []string, timeouts HTTPTimeouts, srv *Server) *http.Server {
|
||||
// Wrap the CORS-handler within a host-handler
|
||||
handler := newCorsHandler(srv, cors)
|
||||
handler = newVHostHandler(vhosts, handler)
|
||||
handler = http.TimeoutHandler(handler, writeTimeout, `{"error":"http server timeout"}`)
|
||||
log.Info("NewHTTPServer", "writeTimeout", writeTimeout)
|
||||
|
||||
// Make sure timeout values are meaningful
|
||||
if timeouts.ReadTimeout < time.Second {
|
||||
log.Warn("Sanitizing invalid HTTP read timeout", "provided", timeouts.ReadTimeout, "updated", DefaultHTTPTimeouts.ReadTimeout)
|
||||
timeouts.ReadTimeout = DefaultHTTPTimeouts.ReadTimeout
|
||||
}
|
||||
if timeouts.WriteTimeout < time.Second {
|
||||
log.Warn("Sanitizing invalid HTTP write timeout", "provided", timeouts.WriteTimeout, "updated", DefaultHTTPTimeouts.WriteTimeout)
|
||||
timeouts.WriteTimeout = DefaultHTTPTimeouts.WriteTimeout
|
||||
}
|
||||
if timeouts.IdleTimeout < time.Second {
|
||||
log.Warn("Sanitizing invalid HTTP idle timeout", "provided", timeouts.IdleTimeout, "updated", DefaultHTTPTimeouts.IdleTimeout)
|
||||
timeouts.IdleTimeout = DefaultHTTPTimeouts.IdleTimeout
|
||||
}
|
||||
|
||||
// PR #469: return http code 503 and error message to client when timeout
|
||||
handler = http.TimeoutHandler(handler, timeouts.WriteTimeout, `{"error":"http server timeout"}`)
|
||||
log.Info("NewHTTPServer", "writeTimeout", timeouts.WriteTimeout)
|
||||
|
||||
// Bundle and start the HTTP server
|
||||
return &http.Server{
|
||||
Handler: handler,
|
||||
ReadTimeout: 5 * time.Second,
|
||||
WriteTimeout: writeTimeout + time.Second,
|
||||
IdleTimeout: 120 * time.Second,
|
||||
ReadTimeout: timeouts.ReadTimeout,
|
||||
WriteTimeout: timeouts.WriteTimeout + time.Second,
|
||||
IdleTimeout: timeouts.IdleTimeout,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue