diff --git a/sender.go b/sender.go index 362a5bf..329c363 100644 --- a/sender.go +++ b/sender.go @@ -273,6 +273,10 @@ func (sender *Sender) popNextMessage() *Message { func (sender *Sender) requeue(msg *Message, bytesSent uint64) { sender.requeueLock.Lock() defer sender.requeueLock.Unlock() + // if icebox has been closed, return early to avoid requeuing messages to a closed sender + if sender.icebox == nil { + return + } msg.bytesSent += bytesSent if msg.bytesSent <= msg.bytesAcked+kMaxUnackedBytes { // requeue it so it can send its next frame later diff --git a/sender_test.go b/sender_test.go index 77f814f..6074d4a 100644 --- a/sender_test.go +++ b/sender_test.go @@ -72,3 +72,45 @@ func TestStopSenderClearsAllMessageQueues(t *testing.T) { assert.Equal(t, 0, len(sender.icebox)) } + +func TestSenderIceboxPanicAfterClosure(t *testing.T) { + + blipContextEchoServer, err := NewContext(defaultContextOptions) + if err != nil { + t.Fatal(err) + } + + server := blipContextEchoServer.WebSocketServer() + http.Handle("/TestSenderIceboxPanicAfterClosure", server) + listener, err := net.Listen("tcp", ":0") + if err != nil { + t.Fatal(err) + } + go func() { + t.Error(http.Serve(listener, nil)) + }() + + blipContextEchoClient, err := NewContext(defaultContextOptions) + if err != nil { + t.Fatal(err) + } + port := listener.Addr().(*net.TCPAddr).Port + destUrl := fmt.Sprintf("ws://localhost:%d/TestSenderIceboxPanicAfterClosure", port) + sender, err := blipContextEchoClient.Dial(destUrl) + if err != nil { + t.Fatalf("Error opening WebSocket: %v", err) + } + + // close sender + sender.Close() + + // try requeueing messages after closure + for i := 1; i < 20; i++ { + msg := NewRequest() + msgProp := Properties{ + "id": fmt.Sprint(i), + } + msg.Properties = msgProp + sender.requeue(msg, 500000) + } +}