From c5371457ee775534ef1aaab0106e8acebf1630b9 Mon Sep 17 00:00:00 2001 From: Benjamin Hallion Date: Thu, 25 May 2023 12:34:29 +0200 Subject: [PATCH 1/2] conn_test: Add TestConcurrentClosePing Updates #298 --- conn_test.go | 23 +++++++++++++++++++++++ read.go | 1 - 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/conn_test.go b/conn_test.go index c814ca28..3df6c64a 100644 --- a/conn_test.go +++ b/conn_test.go @@ -553,3 +553,26 @@ func assertClose(tb testing.TB, c *websocket.Conn) { err := c.Close(websocket.StatusNormalClosure, "") assert.Success(tb, err) } + +func TestConcurrentClosePing(t *testing.T) { + t.Parallel() + for i := 0; i < 64; i++ { + func() { + c1, c2 := wstest.Pipe(nil, nil) + defer c1.CloseNow() + defer c2.CloseNow() + c1.CloseRead(context.Background()) + c2.CloseRead(context.Background()) + go func() { + for range time.Tick(time.Millisecond) { + if err := c1.Ping(context.Background()); err != nil { + return + } + } + }() + + time.Sleep(10 * time.Millisecond) + assert.Success(t, c1.Close(websocket.StatusNormalClosure, "")) + }() + } +} diff --git a/read.go b/read.go index bf4362df..6d0e9aa9 100644 --- a/read.go +++ b/read.go @@ -1,4 +1,3 @@ -//go:build !js // +build !js package websocket From 69f55f34aacbc9979a6c4b88190f3d7e6b7fa968 Mon Sep 17 00:00:00 2001 From: Benjamin Hallion Date: Thu, 25 May 2023 12:34:29 +0200 Subject: [PATCH 2/2] read.go: Avoid handling ping after close frame has been sent Closes #298 --- read.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/read.go b/read.go index 6d0e9aa9..d7facb31 100644 --- a/read.go +++ b/read.go @@ -286,6 +286,13 @@ func (c *Conn) handleControl(ctx context.Context, h header) (err error) { switch h.opcode { case opPing: + c.closeMu.Lock() + wroteClose := c.wroteClose + c.closeMu.Unlock() + if wroteClose { + // Cannot respond to ping with a pong because we already sent a close frame. + return nil + } return c.writeControl(ctx, opPong, b) case opPong: c.activePingsMu.Lock()