mirror of
https://github.com/fluencelabs/tendermint
synced 2025-04-24 22:32:15 +00:00
rpc: make max_body_bytes and max_header_bytes configurable (#3818)
* rpc: make max_body_bytes and max_header_bytes configurable * update changelog pending
This commit is contained in:
parent
9e4cd19878
commit
51b3428f5c
@ -21,5 +21,6 @@ program](https://hackerone.com/tendermint).
|
||||
### IMPROVEMENTS:
|
||||
|
||||
- [abci] \#3809 Recover from application panics in `server/socket_server.go` to allow socket cleanup (@ruseinov)
|
||||
- [rpc] \#3818 Make `max_body_bytes` and `max_header_bytes` configurable
|
||||
|
||||
### BUG FIXES:
|
||||
|
@ -351,6 +351,12 @@ type RPCConfig struct {
|
||||
// See https://github.com/tendermint/tendermint/issues/3435
|
||||
TimeoutBroadcastTxCommit time.Duration `mapstructure:"timeout_broadcast_tx_commit"`
|
||||
|
||||
// Maximum size of request body, in bytes
|
||||
MaxBodyBytes int64 `mapstructure:"max_body_bytes"`
|
||||
|
||||
// Maximum size of request header, in bytes
|
||||
MaxHeaderBytes int `mapstructure:"max_header_bytes"`
|
||||
|
||||
// The path to a file containing certificate that is used to create the HTTPS server.
|
||||
// Migth be either absolute path or path related to tendermint's config directory.
|
||||
//
|
||||
@ -385,6 +391,9 @@ func DefaultRPCConfig() *RPCConfig {
|
||||
MaxSubscriptionsPerClient: 5,
|
||||
TimeoutBroadcastTxCommit: 10 * time.Second,
|
||||
|
||||
MaxBodyBytes: int64(1000000), // 1MB
|
||||
MaxHeaderBytes: 1 << 20, // same as the net/http default
|
||||
|
||||
TLSCertFile: "",
|
||||
TLSKeyFile: "",
|
||||
}
|
||||
@ -417,6 +426,12 @@ func (cfg *RPCConfig) ValidateBasic() error {
|
||||
if cfg.TimeoutBroadcastTxCommit < 0 {
|
||||
return errors.New("timeout_broadcast_tx_commit can't be negative")
|
||||
}
|
||||
if cfg.MaxBodyBytes < 0 {
|
||||
return errors.New("max_body_bytes can't be negative")
|
||||
}
|
||||
if cfg.MaxHeaderBytes < 0 {
|
||||
return errors.New("max_header_bytes can't be negative")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -192,6 +192,12 @@ max_subscriptions_per_client = {{ .RPC.MaxSubscriptionsPerClient }}
|
||||
# See https://github.com/tendermint/tendermint/issues/3435
|
||||
timeout_broadcast_tx_commit = "{{ .RPC.TimeoutBroadcastTxCommit }}"
|
||||
|
||||
# Maximum size of request body, in bytes
|
||||
max_body_bytes = {{ .RPC.MaxBodyBytes }}
|
||||
|
||||
# Maximum size of request header, in bytes
|
||||
max_header_bytes = {{ .RPC.MaxHeaderBytes }}
|
||||
|
||||
# The path to a file containing certificate that is used to create the HTTPS server.
|
||||
# Migth be either absolute path or path related to tendermint's config directory.
|
||||
# If the certificate is signed by a certificate authority,
|
||||
|
@ -138,6 +138,12 @@ max_subscriptions_per_client = 5
|
||||
# See https://github.com/tendermint/tendermint/issues/3435
|
||||
timeout_broadcast_tx_commit = "10s"
|
||||
|
||||
# Maximum size of request body, in bytes
|
||||
max_body_bytes = {{ .RPC.MaxBodyBytes }}
|
||||
|
||||
# Maximum size of request header, in bytes
|
||||
max_header_bytes = {{ .RPC.MaxHeaderBytes }}
|
||||
|
||||
# The path to a file containing certificate that is used to create the HTTPS server.
|
||||
# Migth be either absolute path or path related to tendermint's config directory.
|
||||
# If the certificate is signed by a certificate authority,
|
||||
|
25
node/node.go
25
node/node.go
@ -820,6 +820,17 @@ func (n *Node) startRPC() ([]net.Listener, error) {
|
||||
rpccore.AddUnsafeRoutes()
|
||||
}
|
||||
|
||||
config := rpcserver.DefaultConfig()
|
||||
config.MaxBodyBytes = n.config.RPC.MaxBodyBytes
|
||||
config.MaxHeaderBytes = n.config.RPC.MaxHeaderBytes
|
||||
config.MaxOpenConnections = n.config.RPC.MaxOpenConnections
|
||||
// If necessary adjust global WriteTimeout to ensure it's greater than
|
||||
// TimeoutBroadcastTxCommit.
|
||||
// See https://github.com/tendermint/tendermint/issues/3435
|
||||
if config.WriteTimeout <= n.config.RPC.TimeoutBroadcastTxCommit {
|
||||
config.WriteTimeout = n.config.RPC.TimeoutBroadcastTxCommit + 1*time.Second
|
||||
}
|
||||
|
||||
// we may expose the rpc over both a unix and tcp socket
|
||||
listeners := make([]net.Listener, len(listenAddrs))
|
||||
for i, listenAddr := range listenAddrs {
|
||||
@ -832,20 +843,12 @@ func (n *Node) startRPC() ([]net.Listener, error) {
|
||||
if err != nil && err != tmpubsub.ErrSubscriptionNotFound {
|
||||
wmLogger.Error("Failed to unsubscribe addr from events", "addr", remoteAddr, "err", err)
|
||||
}
|
||||
}))
|
||||
}),
|
||||
rpcserver.ReadLimit(config.MaxBodyBytes),
|
||||
)
|
||||
wm.SetLogger(wmLogger)
|
||||
mux.HandleFunc("/websocket", wm.WebsocketHandler)
|
||||
rpcserver.RegisterRPCFuncs(mux, rpccore.Routes, coreCodec, rpcLogger)
|
||||
|
||||
config := rpcserver.DefaultConfig()
|
||||
config.MaxOpenConnections = n.config.RPC.MaxOpenConnections
|
||||
// If necessary adjust global WriteTimeout to ensure it's greater than
|
||||
// TimeoutBroadcastTxCommit.
|
||||
// See https://github.com/tendermint/tendermint/issues/3435
|
||||
if config.WriteTimeout <= n.config.RPC.TimeoutBroadcastTxCommit {
|
||||
config.WriteTimeout = n.config.RPC.TimeoutBroadcastTxCommit + 1*time.Second
|
||||
}
|
||||
|
||||
listener, err := rpcserver.Listen(
|
||||
listenAddr,
|
||||
config,
|
||||
|
@ -448,6 +448,9 @@ type wsConnection struct {
|
||||
// Send pings to server with this period. Must be less than readWait, but greater than zero.
|
||||
pingPeriod time.Duration
|
||||
|
||||
// Maximum message size.
|
||||
readLimit int64
|
||||
|
||||
// callback which is called upon disconnect
|
||||
onDisconnect func(remoteAddr string)
|
||||
|
||||
@ -467,7 +470,6 @@ func NewWSConnection(
|
||||
cdc *amino.Codec,
|
||||
options ...func(*wsConnection),
|
||||
) *wsConnection {
|
||||
baseConn.SetReadLimit(maxBodyBytes)
|
||||
wsc := &wsConnection{
|
||||
remoteAddr: baseConn.RemoteAddr().String(),
|
||||
baseConn: baseConn,
|
||||
@ -481,6 +483,7 @@ func NewWSConnection(
|
||||
for _, option := range options {
|
||||
option(wsc)
|
||||
}
|
||||
wsc.baseConn.SetReadLimit(wsc.readLimit)
|
||||
wsc.BaseService = *cmn.NewBaseService(nil, "wsConnection", wsc)
|
||||
return wsc
|
||||
}
|
||||
@ -525,6 +528,14 @@ func PingPeriod(pingPeriod time.Duration) func(*wsConnection) {
|
||||
}
|
||||
}
|
||||
|
||||
// ReadLimit sets the maximum size for reading message.
|
||||
// It should only be used in the constructor - not Goroutine-safe.
|
||||
func ReadLimit(readLimit int64) func(*wsConnection) {
|
||||
return func(wsc *wsConnection) {
|
||||
wsc.readLimit = readLimit
|
||||
}
|
||||
}
|
||||
|
||||
// OnStart implements cmn.Service by starting the read and write routines. It
|
||||
// blocks until the connection closes.
|
||||
func (wsc *wsConnection) OnStart() error {
|
||||
|
@ -26,6 +26,11 @@ type Config struct {
|
||||
ReadTimeout time.Duration
|
||||
// mirrors http.Server#WriteTimeout
|
||||
WriteTimeout time.Duration
|
||||
// MaxBodyBytes controls the maximum number of bytes the
|
||||
// server will read parsing the request body.
|
||||
MaxBodyBytes int64
|
||||
// mirrors http.Server#MaxHeaderBytes
|
||||
MaxHeaderBytes int
|
||||
}
|
||||
|
||||
// DefaultConfig returns a default configuration.
|
||||
@ -34,28 +39,21 @@ func DefaultConfig() *Config {
|
||||
MaxOpenConnections: 0, // unlimited
|
||||
ReadTimeout: 10 * time.Second,
|
||||
WriteTimeout: 10 * time.Second,
|
||||
MaxBodyBytes: int64(1000000), // 1MB
|
||||
MaxHeaderBytes: 1 << 20, // same as the net/http default
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
// maxBodyBytes controls the maximum number of bytes the
|
||||
// server will read parsing the request body.
|
||||
maxBodyBytes = int64(1000000) // 1MB
|
||||
|
||||
// same as the net/http default
|
||||
maxHeaderBytes = 1 << 20
|
||||
)
|
||||
|
||||
// StartHTTPServer takes a listener and starts an HTTP server with the given handler.
|
||||
// It wraps handler with RecoverAndLogHandler.
|
||||
// NOTE: This function blocks - you may want to call it in a go-routine.
|
||||
func StartHTTPServer(listener net.Listener, handler http.Handler, logger log.Logger, config *Config) error {
|
||||
logger.Info(fmt.Sprintf("Starting RPC HTTP server on %s", listener.Addr()))
|
||||
s := &http.Server{
|
||||
Handler: RecoverAndLogHandler(maxBytesHandler{h: handler, n: maxBodyBytes}, logger),
|
||||
Handler: RecoverAndLogHandler(maxBytesHandler{h: handler, n: config.MaxBodyBytes}, logger),
|
||||
ReadTimeout: config.ReadTimeout,
|
||||
WriteTimeout: config.WriteTimeout,
|
||||
MaxHeaderBytes: maxHeaderBytes,
|
||||
MaxHeaderBytes: config.MaxHeaderBytes,
|
||||
}
|
||||
err := s.Serve(listener)
|
||||
logger.Info("RPC HTTP server stopped", "err", err)
|
||||
@ -75,10 +73,10 @@ func StartHTTPAndTLSServer(
|
||||
logger.Info(fmt.Sprintf("Starting RPC HTTPS server on %s (cert: %q, key: %q)",
|
||||
listener.Addr(), certFile, keyFile))
|
||||
s := &http.Server{
|
||||
Handler: RecoverAndLogHandler(maxBytesHandler{h: handler, n: maxBodyBytes}, logger),
|
||||
Handler: RecoverAndLogHandler(maxBytesHandler{h: handler, n: config.MaxBodyBytes}, logger),
|
||||
ReadTimeout: config.ReadTimeout,
|
||||
WriteTimeout: config.WriteTimeout,
|
||||
MaxHeaderBytes: maxHeaderBytes,
|
||||
MaxHeaderBytes: config.MaxHeaderBytes,
|
||||
}
|
||||
err := s.ServeTLS(listener, certFile, keyFile)
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user