fix(tunnel): data race in CloseOnIdle and goroutine leak in sniffingWebsocketFrame
- Use write lock (Lock) instead of read lock (RLock) in CloseOnIdle since it modifies the close channel, preventing a race with Close() that could panic on double-close of channel. - Buffer sniffingWebsocketFrame errc to capacity 2 and close both connections on first error to ensure the remaining copy goroutine unblocks and exits cleanly.
This commit is contained in:
@@ -440,8 +440,8 @@ func (ep *entrypoint) handleUpgradeResponse(ctx context.Context, rw io.ReadWrite
|
|||||||
return xnet.Pipe(ctx, rw, backConn)
|
return xnet.Pipe(ctx, rw, backConn)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ep *entrypoint) sniffingWebsocketFrame(ctx context.Context, rw, cc io.ReadWriter, ro *xrecorder.HandlerRecorderObject, log logger.Logger) error {
|
func (ep *entrypoint) sniffingWebsocketFrame(ctx context.Context, rw, cc io.ReadWriteCloser, ro *xrecorder.HandlerRecorderObject, log logger.Logger) error {
|
||||||
errc := make(chan error, 1)
|
errc := make(chan error, 2)
|
||||||
|
|
||||||
sampleRate := ep.websocketSampleRate
|
sampleRate := ep.websocketSampleRate
|
||||||
if sampleRate == 0 {
|
if sampleRate == 0 {
|
||||||
@@ -503,6 +503,9 @@ func (ep *entrypoint) sniffingWebsocketFrame(ctx context.Context, rw, cc io.Read
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
<-errc
|
||||||
|
rw.Close()
|
||||||
|
cc.Close()
|
||||||
<-errc
|
<-errc
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -230,8 +230,8 @@ func (t *Tunnel) Close() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *Tunnel) CloseOnIdle() bool {
|
func (t *Tunnel) CloseOnIdle() bool {
|
||||||
t.mu.RLock()
|
t.mu.Lock()
|
||||||
defer t.mu.RUnlock()
|
defer t.mu.Unlock()
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case <-t.close:
|
case <-t.close:
|
||||||
|
|||||||
Reference in New Issue
Block a user