Skip to content

Commit 07d6409

Browse files
committed
fix: suppress net.ErrClosed on concurrent Close
Close and CloseNow return net.ErrClosed when the read loop or write path wins the casClosing race. The defer that suppresses net.ErrClosed is only registered on the winner path, so the user-facing call surfaces a wrapped "use of closed network connection" even though the close succeeded. Move the defer before the casClosing check so both paths suppress net.ErrClosed, matching the godoc contract that additional calls to Close are no-ops.
1 parent d099e16 commit 07d6409

2 files changed

Lines changed: 10 additions & 18 deletions

File tree

close.go

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -98,20 +98,16 @@ func CloseStatus(err error) StatusCode {
9898
// complete.
9999
func (c *Conn) Close(code StatusCode, reason string) (err error) {
100100
defer errd.Wrap(&err, "failed to close WebSocket")
101-
102-
if c.casClosing() {
103-
err = c.waitGoroutines()
104-
if err != nil {
105-
return err
106-
}
107-
return net.ErrClosed
108-
}
109101
defer func() {
110102
if errors.Is(err, net.ErrClosed) {
111103
err = nil
112104
}
113105
}()
114106

107+
if c.casClosing() {
108+
return c.waitGoroutines()
109+
}
110+
115111
err = c.closeHandshake(code, reason)
116112

117113
err2 := c.close()
@@ -131,20 +127,16 @@ func (c *Conn) Close(code StatusCode, reason string) (err error) {
131127
// Use when you do not want the overhead of the close handshake.
132128
func (c *Conn) CloseNow() (err error) {
133129
defer errd.Wrap(&err, "failed to immediately close WebSocket")
134-
135-
if c.casClosing() {
136-
err = c.waitGoroutines()
137-
if err != nil {
138-
return err
139-
}
140-
return net.ErrClosed
141-
}
142130
defer func() {
143131
if errors.Is(err, net.ErrClosed) {
144132
err = nil
145133
}
146134
}()
147135

136+
if c.casClosing() {
137+
return c.waitGoroutines()
138+
}
139+
148140
err = c.close()
149141

150142
err2 := c.waitGoroutines()

conn_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -397,8 +397,8 @@ func TestConn(t *testing.T) {
397397
assert.Success(t, err2)
398398
err1 = c1.CloseNow()
399399
err2 = c2.CloseNow()
400-
assert.ErrorIs(t, websocket.ErrClosed, err1)
401-
assert.ErrorIs(t, websocket.ErrClosed, err2)
400+
assert.Success(t, err1)
401+
assert.Success(t, err2)
402402
})
403403

404404
t.Run("MidReadClose", func(t *testing.T) {

0 commit comments

Comments
 (0)