Browse Source

rpc: make max_body_bytes and max_header_bytes configurable (#3818)

* rpc: make max_body_bytes and max_header_bytes configurable

* update changelog pending
pull/3926/head
Jun Kimura 6 years ago
committed by Jack Zampolin
parent
commit
5d7e22a53c
7 changed files with 65 additions and 25 deletions
  1. +1
    -0
      CHANGELOG_PENDING.md
  2. +15
    -0
      config/config.go
  3. +6
    -0
      config/toml.go
  4. +6
    -0
      docs/tendermint-core/configuration.md
  5. +14
    -11
      node/node.go
  6. +12
    -1
      rpc/lib/server/handlers.go
  7. +11
    -13
      rpc/lib/server/http_server.go

+ 1
- 0
CHANGELOG_PENDING.md View File

@ -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:

+ 15
- 0
config/config.go View File

@ -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
}


+ 6
- 0
config/toml.go View File

@ -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,


+ 6
- 0
docs/tendermint-core/configuration.md View File

@ -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,


+ 14
- 11
node/node.go View File

@ -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,


+ 12
- 1
rpc/lib/server/handlers.go View File

@ -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 {


+ 11
- 13
rpc/lib/server/http_server.go View File

@ -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…
Cancel
Save