PingInterval/PongTimeout were configured but unused, so a half-open peer
(TCP open but silent) left both proxy goroutines and the handler blocked
in ReadMessage forever. Wire both directions: read deadline refreshed by
real traffic or pong, plus a sidecar ping goroutine (WriteControl is
safe to call concurrently with WriteMessage). Add regression test
TestWebSocketProxy_ReapsSilentBackend_Keepalive proving a silent backend
is reaped via the read deadline instead of hanging.