Skip to content

Commit fb8ea43

Browse files
committed
Defer application of http.TimeoutHandler until endpoint middleware so specific endpoints can opt out
1 parent 900f162 commit fb8ea43

File tree

5 files changed

+24
-5
lines changed

5 files changed

+24
-5
lines changed

api/server/httprest/server.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@ func New(ctx context.Context, opts ...Option) (*Server, error) {
4848
handler = middleware.MiddlewareChain(g.cfg.router, g.cfg.middlewares)
4949
if g.cfg.timeout > 0*time.Second {
5050
defaultReadHeaderTimeout = g.cfg.timeout
51-
handler = http.TimeoutHandler(handler, g.cfg.timeout, "request timed out")
5251
}
5352
g.server = &http.Server{
5453
Addr: g.cfg.httpAddr,

beacon-chain/node/node.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -938,6 +938,7 @@ func (b *BeaconNode) registerRPCService(router *http.ServeMux) error {
938938
mockEth1DataVotes := b.cliCtx.Bool(flags.InteropMockEth1DataVotesFlag.Name)
939939
maxMsgSize := b.cliCtx.Int(cmd.GrpcMaxCallRecvMsgSizeFlag.Name)
940940
enableDebugRPCEndpoints := !b.cliCtx.Bool(flags.DisableDebugRPCEndpoints.Name)
941+
apiTimeout := b.cliCtx.Duration(cmd.ApiTimeoutFlag.Name)
941942

942943
p2pService := b.fetchP2P()
943944
rpcService := rpc.NewService(b.ctx, &rpc.Config{
@@ -994,6 +995,7 @@ func (b *BeaconNode) registerRPCService(router *http.ServeMux) error {
994995
TrackedValidatorsCache: b.trackedValidatorsCache,
995996
PayloadIDCache: b.payloadIDCache,
996997
LCStore: b.lcStore,
998+
ApiTimeout: apiTimeout,
997999
})
9981000

9991001
return b.services.RegisterService(rpcService)

beacon-chain/rpc/endpoints.go

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ type endpoint struct {
3333
middleware []middleware.Middleware
3434
handler http.HandlerFunc
3535
methods []string
36+
37+
errorMiddlewareIncompatible bool
38+
timeoutHandlerIncompatible bool
3639
}
3740

3841
// responseWriter is the wrapper to http Response writer.
@@ -63,9 +66,9 @@ func (e *endpoint) handlerWithMiddleware() http.HandlerFunc {
6366
)
6467

6568
return func(w http.ResponseWriter, r *http.Request) {
66-
// SSE errors are handled separately to avoid interference with the streaming
67-
// mechanism and ensure accurate error tracking.
68-
if e.template == "/eth/v1/events" {
69+
// Some handlers (i.e. SSE) handle errors separately to avoid interference with
70+
// the streaming mechanism and ensure accurate error tracking.
71+
if e.errorMiddlewareIncompatible {
6972
handler.ServeHTTP(w, r)
7073
return
7174
}
@@ -1164,6 +1167,12 @@ func (s *Service) eventsEndpoints() []endpoint {
11641167
},
11651168
handler: server.StreamEvents,
11661169
methods: []string{http.MethodGet},
1170+
1171+
// events endpoint handles errors separately
1172+
errorMiddlewareIncompatible: true,
1173+
// http.TimeoutHandler causes this handler to behave incorrectly, since it uses SetDeadline
1174+
// on the underlying net/http response
1175+
timeoutHandlerIncompatible: true,
11671176
},
11681177
}
11691178
}

beacon-chain/rpc/service.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"net"
99
"net/http"
1010
"sync"
11+
"time"
1112

1213
"github.com/OffchainLabs/prysm/v6/beacon-chain/blockchain"
1314
"github.com/OffchainLabs/prysm/v6/beacon-chain/builder"
@@ -125,6 +126,7 @@ type Config struct {
125126
TrackedValidatorsCache *cache.TrackedValidatorsCache
126127
PayloadIDCache *cache.PayloadIDCache
127128
LCStore *lightClient.Store
129+
ApiTimeout time.Duration
128130
}
129131

130132
// NewService instantiates a new RPC service instance that will
@@ -301,9 +303,13 @@ func NewService(ctx context.Context, cfg *Config) *Service {
301303
endpoints := s.endpoints(s.cfg.EnableDebugRPCEndpoints, blocker, stater, rewardFetcher, validatorServer, coreService, ch)
302304
for _, e := range endpoints {
303305
for i := range e.methods {
306+
handler := e.handlerWithMiddleware()
307+
if s.cfg.ApiTimeout > 0 && !e.timeoutHandlerIncompatible {
308+
handler = http.TimeoutHandler(handler, s.cfg.ApiTimeout, "request timed out").ServeHTTP
309+
}
304310
s.cfg.Router.HandleFunc(
305311
fmt.Sprintf("%s %s", e.methods[i], e.template),
306-
e.handlerWithMiddleware(),
312+
handler,
307313
)
308314
}
309315
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
### Fixed
2+
3+
- Fixed /eth/v1/events incompatibility with --api-timeout argument

0 commit comments

Comments
 (0)