mirror of
https://github.com/lukaszraczylo/graphql-monitoring-proxy.git
synced 2026-10-21 06:37:21 +00:00
fix(websocket): tear down peer connection and bound backend messages
Two defects in the bidirectional proxy: 1. Goroutine/socket leak on client disconnect. proxyClientToBackend and proxyBackendToClient each block on their own Read; when the client drops, the client-direction goroutine returns but the backend-direction goroutine stays blocked on backend.ReadMessage, so wg.Wait() never returns and the goroutine plus backend socket leak until the backend independently closes or sends. Each direction now closes the opposite connection on exit, unblocking the peer. 2. Backend->client messages were unbounded. client.SetReadLimit only bound what the client could send; a large or misbehaving backend could push arbitrarily large frames through. backend.SetReadLimit now bounds it. Tests: TestWebSocketProxy_TeardownOnClientDisconnect (backend must be closed after client disconnect), TestWebSocketProxy_BackendReadLimit (connection torn down when backend exceeds the limit).
This commit is contained in:
@@ -207,6 +207,11 @@ func (wsp *WebSocketProxy) handleConnection(ctx context.Context, clientConn *web
|
||||
})
|
||||
}
|
||||
|
||||
// Bound messages read from the backend as well, so a large or
|
||||
// misbehaving backend cannot force us to forward an unbounded frame to the
|
||||
// client (the client-side limit only bounds what the client can send us).
|
||||
backendConn.SetReadLimit(wsp.maxMessageSize)
|
||||
|
||||
// Set up bidirectional proxying
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(2)
|
||||
@@ -214,12 +219,19 @@ func (wsp *WebSocketProxy) handleConnection(ctx context.Context, clientConn *web
|
||||
// Client -> Backend
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
// When the client side finishes (e.g. the client disconnected), close
|
||||
// the backend so the reverse goroutine's blocked read returns instead
|
||||
// of leaking the goroutine and holding the backend connection open.
|
||||
defer func() { _ = backendConn.Close() }()
|
||||
wsp.proxyClientToBackend(ctx, clientConn, backendConn, connectionID)
|
||||
}()
|
||||
|
||||
// Backend -> Client
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
// Symmetric teardown: when the backend side finishes, close the
|
||||
// client so the client-direction goroutine isn't left blocked either.
|
||||
defer func() { _ = clientConn.Close() }()
|
||||
wsp.proxyBackendToClient(ctx, backendConn, clientConn, connectionID)
|
||||
}()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user