diff --git a/server/config.go b/server/config.go index 0f05ccea..8f602971 100644 --- a/server/config.go +++ b/server/config.go @@ -23,6 +23,7 @@ const ( defaultMaxLogFileSize = 10 defaultRPCPort = 50002 defaultRESTPort = 8080 + defaultMaxGrpcMsgSize = 8 * 1024 * 1024 defaultEpochDuration = 30 * time.Second defaultPhaseShift = 15 * time.Second @@ -30,19 +31,20 @@ const ( ) type Config struct { - Genesis Genesis `long:"genesis-time" description:"Genesis timestamp in RFC3339 format"` - PoetDir string `long:"poetdir" description:"The base directory that contains poet's data, logs, configuration file, etc."` - ConfigFile string `long:"configfile" description:"Path to configuration file" short:"c"` - DataDir string `long:"datadir" description:"The directory to store poet's data within." short:"b"` - DbDir string `long:"dbdir" description:"The directory to store DBs within"` - LogDir string `long:"logdir" description:"Directory to log output."` - DebugLog bool `long:"debuglog" description:"Enable debug logs"` - JSONLog bool `long:"jsonlog" description:"Whether to log in JSON format"` - MaxLogFiles int `long:"maxlogfiles" description:"Maximum logfiles to keep (0 for no rotation)"` - MaxLogFileSize int `long:"maxlogfilesize" description:"Maximum logfile size in MB"` - RawRPCListener string `long:"rpclisten" description:"The interface/port/socket to listen for RPC connections" short:"r"` - RawRESTListener string `long:"restlisten" description:"The interface/port/socket to listen for REST connections" short:"w"` - MetricsPort *uint16 `long:"metrics-port" description:"The port to expose metrics"` + Genesis Genesis `long:"genesis-time" description:"Genesis timestamp in RFC3339 format"` + PoetDir string `long:"poetdir" description:"The base directory that contains poet's data, logs, configuration file, etc."` + ConfigFile string `long:"configfile" description:"Path to configuration file" short:"c"` + DataDir string `long:"datadir" description:"The directory to store poet's data within." short:"b"` + DbDir string `long:"dbdir" description:"The directory to store DBs within"` + LogDir string `long:"logdir" description:"Directory to log output."` + DebugLog bool `long:"debuglog" description:"Enable debug logs"` + JSONLog bool `long:"jsonlog" description:"Whether to log in JSON format"` + MaxLogFiles int `long:"maxlogfiles" description:"Maximum logfiles to keep (0 for no rotation)"` + MaxLogFileSize int `long:"maxlogfilesize" description:"Maximum logfile size in MB"` + RawRPCListener string `long:"rpclisten" description:"The interface/port/socket to listen for RPC connections" short:"r"` + RawRESTListener string `long:"restlisten" description:"The interface/port/socket to listen for REST connections" short:"w"` + MetricsPort *uint16 `long:"metrics-port" description:"The port to expose metrics"` + MaxGrpcRespSize int `long:"max-grpc-resp-size" description:"Maximum size of GRPC response in bytes"` CPUProfile string `long:"cpuprofile" description:"Write CPU profile to the specified file"` Profile string `long:"profile" description:"Enable HTTP profiling on given port -- must be between 1024 and 65535"` diff --git a/server/rest_gateway_test.go b/server/rest_gateway_test.go new file mode 100644 index 00000000..f7a71ac9 --- /dev/null +++ b/server/rest_gateway_test.go @@ -0,0 +1,46 @@ +package server_test + +import ( + "context" + "io" + "net/http" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.uber.org/zap/zaptest" + "golang.org/x/sync/errgroup" + + "github.com/spacemeshos/poet/logging" + "github.com/spacemeshos/poet/server" +) + +func TestConfiguringMaxGrpcRespSize(t *testing.T) { + req := require.New(t) + cfg := server.DefaultConfig() + cfg.PoetDir = t.TempDir() + cfg.MaxGrpcRespSize = 16 + cfg.RawRPCListener = randomHost + cfg.RawRESTListener = randomHost + + ctx := logging.NewContext(context.Background(), zaptest.NewLogger(t)) + ctx, cancel := context.WithCancel(ctx) + defer cancel() + + srv := spawnPoetServer(ctx, t, *cfg) + t.Cleanup(func() { assert.NoError(t, srv.Close()) }) + + var eg errgroup.Group + eg.Go(func() error { + return srv.Start(ctx) + }) + t.Cleanup(func() { assert.NoError(t, eg.Wait()) }) + + resp, err := http.Get("http://" + srv.GrpcRestProxyAddr().String() + "/v1/info") + req.NoError(err) + + defer resp.Body.Close() + data, err := io.ReadAll(resp.Body) + req.NoError(err) + req.Contains(string(data), "received message larger than max") +} diff --git a/server/server.go b/server/server.go index c52bd56f..7fba01a5 100644 --- a/server/server.go +++ b/server/server.go @@ -207,6 +207,7 @@ func (s *Server) Start(ctx context.Context) error { s.rpcListener.Addr().String(), []grpc.DialOption{ grpc.WithTransportCredentials(insecure.NewCredentials()), + grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(s.cfg.MaxGrpcRespSize)), }, ) if err != nil { diff --git a/server/server_test.go b/server/server_test.go index bea6cebe..cccbdf34 100644 --- a/server/server_test.go +++ b/server/server_test.go @@ -30,15 +30,23 @@ import ( const randomHost = "localhost:0" -func spawnPoet(ctx context.Context, t *testing.T, cfg server.Config) (*server.Server, api.PoetServiceClient) { +func spawnPoetServer(ctx context.Context, t *testing.T, cfg server.Config) *server.Server { t.Helper() req := require.New(t) server.SetupConfig(&cfg) - srv, err := server.New(ctx, cfg) req.NoError(err) + return srv +} + +func spawnPoet(ctx context.Context, t *testing.T, cfg server.Config) (*server.Server, api.PoetServiceClient) { + t.Helper() + req := require.New(t) + + srv := spawnPoetServer(ctx, t, cfg) + conn, err := grpc.DialContext( ctx, srv.GrpcAddr().String(),