mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-07 23:48:36 +00:00
node: fix data race on httpConfig.prefix (#32047)
This fixes a data race when accessing the `httpConfig.prefix` field. This field can be modified while the server is running through `enableRPC`. The fix is storing the prefix in the handler, which is accessed through the atomic pointer. alternative to #32035 fixes https://github.com/ethereum/go-ethereum/issues/32019
This commit is contained in:
parent
e2007e513c
commit
9402187733
1 changed files with 19 additions and 19 deletions
|
|
@ -62,6 +62,7 @@ type rpcEndpointConfig struct {
|
||||||
|
|
||||||
type rpcHandler struct {
|
type rpcHandler struct {
|
||||||
http.Handler
|
http.Handler
|
||||||
|
prefix string
|
||||||
server *rpc.Server
|
server *rpc.Server
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -77,11 +78,11 @@ type httpServer struct {
|
||||||
// HTTP RPC handler things.
|
// HTTP RPC handler things.
|
||||||
|
|
||||||
httpConfig httpConfig
|
httpConfig httpConfig
|
||||||
httpHandler atomic.Value // *rpcHandler
|
httpHandler atomic.Pointer[rpcHandler]
|
||||||
|
|
||||||
// WebSocket handler things.
|
// WebSocket handler things.
|
||||||
wsConfig wsConfig
|
wsConfig wsConfig
|
||||||
wsHandler atomic.Value // *rpcHandler
|
wsHandler atomic.Pointer[rpcHandler]
|
||||||
|
|
||||||
// These are set by setListenAddr.
|
// These are set by setListenAddr.
|
||||||
endpoint string
|
endpoint string
|
||||||
|
|
@ -97,9 +98,6 @@ const (
|
||||||
|
|
||||||
func newHTTPServer(log log.Logger, timeouts rpc.HTTPTimeouts) *httpServer {
|
func newHTTPServer(log log.Logger, timeouts rpc.HTTPTimeouts) *httpServer {
|
||||||
h := &httpServer{log: log, timeouts: timeouts, handlerNames: make(map[string]string)}
|
h := &httpServer{log: log, timeouts: timeouts, handlerNames: make(map[string]string)}
|
||||||
|
|
||||||
h.httpHandler.Store((*rpcHandler)(nil))
|
|
||||||
h.wsHandler.Store((*rpcHandler)(nil))
|
|
||||||
return h
|
return h
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -198,16 +196,16 @@ func (h *httpServer) start() error {
|
||||||
|
|
||||||
func (h *httpServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
func (h *httpServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
// check if ws request and serve if ws enabled
|
// check if ws request and serve if ws enabled
|
||||||
ws := h.wsHandler.Load().(*rpcHandler)
|
ws := h.wsHandler.Load()
|
||||||
if ws != nil && isWebsocket(r) {
|
if ws != nil && isWebsocket(r) {
|
||||||
if checkPath(r, h.wsConfig.prefix) {
|
if checkPath(r, ws.prefix) {
|
||||||
ws.ServeHTTP(w, r)
|
ws.ServeHTTP(w, r)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// if http-rpc is enabled, try to serve request
|
// if http-rpc is enabled, try to serve request
|
||||||
rpc := h.httpHandler.Load().(*rpcHandler)
|
rpc := h.httpHandler.Load()
|
||||||
if rpc != nil {
|
if rpc != nil {
|
||||||
// First try to route in the mux.
|
// First try to route in the mux.
|
||||||
// Requests to a path below root are handled by the mux,
|
// Requests to a path below root are handled by the mux,
|
||||||
|
|
@ -219,7 +217,7 @@ func (h *httpServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if checkPath(r, h.httpConfig.prefix) {
|
if checkPath(r, rpc.prefix) {
|
||||||
rpc.ServeHTTP(w, r)
|
rpc.ServeHTTP(w, r)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -267,14 +265,14 @@ func (h *httpServer) doStop() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Shut down the server.
|
// Shut down the server.
|
||||||
httpHandler := h.httpHandler.Load().(*rpcHandler)
|
httpHandler := h.httpHandler.Load()
|
||||||
wsHandler := h.wsHandler.Load().(*rpcHandler)
|
wsHandler := h.wsHandler.Load()
|
||||||
if httpHandler != nil {
|
if httpHandler != nil {
|
||||||
h.httpHandler.Store((*rpcHandler)(nil))
|
h.httpHandler.Store(nil)
|
||||||
httpHandler.server.Stop()
|
httpHandler.server.Stop()
|
||||||
}
|
}
|
||||||
if wsHandler != nil {
|
if wsHandler != nil {
|
||||||
h.wsHandler.Store((*rpcHandler)(nil))
|
h.wsHandler.Store(nil)
|
||||||
wsHandler.server.Stop()
|
wsHandler.server.Stop()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -315,6 +313,7 @@ func (h *httpServer) enableRPC(apis []rpc.API, config httpConfig) error {
|
||||||
h.httpConfig = config
|
h.httpConfig = config
|
||||||
h.httpHandler.Store(&rpcHandler{
|
h.httpHandler.Store(&rpcHandler{
|
||||||
Handler: NewHTTPHandlerStack(srv, config.CorsAllowedOrigins, config.Vhosts, config.jwtSecret),
|
Handler: NewHTTPHandlerStack(srv, config.CorsAllowedOrigins, config.Vhosts, config.jwtSecret),
|
||||||
|
prefix: config.prefix,
|
||||||
server: srv,
|
server: srv,
|
||||||
})
|
})
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -322,9 +321,9 @@ func (h *httpServer) enableRPC(apis []rpc.API, config httpConfig) error {
|
||||||
|
|
||||||
// disableRPC stops the HTTP RPC handler. This is internal, the caller must hold h.mu.
|
// disableRPC stops the HTTP RPC handler. This is internal, the caller must hold h.mu.
|
||||||
func (h *httpServer) disableRPC() bool {
|
func (h *httpServer) disableRPC() bool {
|
||||||
handler := h.httpHandler.Load().(*rpcHandler)
|
handler := h.httpHandler.Load()
|
||||||
if handler != nil {
|
if handler != nil {
|
||||||
h.httpHandler.Store((*rpcHandler)(nil))
|
h.httpHandler.Store(nil)
|
||||||
handler.server.Stop()
|
handler.server.Stop()
|
||||||
}
|
}
|
||||||
return handler != nil
|
return handler != nil
|
||||||
|
|
@ -350,6 +349,7 @@ func (h *httpServer) enableWS(apis []rpc.API, config wsConfig) error {
|
||||||
h.wsConfig = config
|
h.wsConfig = config
|
||||||
h.wsHandler.Store(&rpcHandler{
|
h.wsHandler.Store(&rpcHandler{
|
||||||
Handler: NewWSHandlerStack(srv.WebsocketHandler(config.Origins), config.jwtSecret),
|
Handler: NewWSHandlerStack(srv.WebsocketHandler(config.Origins), config.jwtSecret),
|
||||||
|
prefix: config.prefix,
|
||||||
server: srv,
|
server: srv,
|
||||||
})
|
})
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -369,9 +369,9 @@ func (h *httpServer) stopWS() {
|
||||||
|
|
||||||
// disableWS disables the WebSocket handler. This is internal, the caller must hold h.mu.
|
// disableWS disables the WebSocket handler. This is internal, the caller must hold h.mu.
|
||||||
func (h *httpServer) disableWS() bool {
|
func (h *httpServer) disableWS() bool {
|
||||||
ws := h.wsHandler.Load().(*rpcHandler)
|
ws := h.wsHandler.Load()
|
||||||
if ws != nil {
|
if ws != nil {
|
||||||
h.wsHandler.Store((*rpcHandler)(nil))
|
h.wsHandler.Store(nil)
|
||||||
ws.server.Stop()
|
ws.server.Stop()
|
||||||
}
|
}
|
||||||
return ws != nil
|
return ws != nil
|
||||||
|
|
@ -379,12 +379,12 @@ func (h *httpServer) disableWS() bool {
|
||||||
|
|
||||||
// rpcAllowed returns true when JSON-RPC over HTTP is enabled.
|
// rpcAllowed returns true when JSON-RPC over HTTP is enabled.
|
||||||
func (h *httpServer) rpcAllowed() bool {
|
func (h *httpServer) rpcAllowed() bool {
|
||||||
return h.httpHandler.Load().(*rpcHandler) != nil
|
return h.httpHandler.Load() != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// wsAllowed returns true when JSON-RPC over WebSocket is enabled.
|
// wsAllowed returns true when JSON-RPC over WebSocket is enabled.
|
||||||
func (h *httpServer) wsAllowed() bool {
|
func (h *httpServer) wsAllowed() bool {
|
||||||
return h.wsHandler.Load().(*rpcHandler) != nil
|
return h.wsHandler.Load() != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// isWebsocket checks the header of an http request for a websocket upgrade request.
|
// isWebsocket checks the header of an http request for a websocket upgrade request.
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue