Close internal Pipes in websocketconn.Conn Close.

Unless something externally called Write after Close, the
writeLoop(ws, pr2) goroutine would run forever, because nothing would
ever close pw2/pr2.
https://bugs.torproject.org/33367#comment:4
This commit is contained in:
David Fifield 2020-02-18 14:10:47 -07:00
parent 1220853a67
commit 380b133155
2 changed files with 30 additions and 0 deletions

View file

@ -24,6 +24,8 @@ func (conn *Conn) Write(b []byte) (n int, err error) {
} }
func (conn *Conn) Close() error { func (conn *Conn) Close() error {
conn.Reader.(*io.PipeReader).Close()
conn.Writer.(*io.PipeWriter).Close()
// Ignore any error in trying to write a Close frame. // Ignore any error in trying to write a Close frame.
_ = conn.Conn.WriteControl(websocket.CloseMessage, []byte{}, time.Now().Add(time.Second)) _ = conn.Conn.WriteControl(websocket.CloseMessage, []byte{}, time.Now().Add(time.Second))
return conn.Conn.Close() return conn.Conn.Close()

View file

@ -233,3 +233,31 @@ func TestConcurrentWrite(t *testing.T) {
t.Fatalf("Write: %v", err) t.Fatalf("Write: %v", err)
} }
} }
// Test that Read and Write methods return errors after Close.
func TestClose(t *testing.T) {
s, c, err := connPair()
if err != nil {
t.Fatal(err)
}
defer c.Close()
err = s.Close()
if err != nil {
t.Fatal(err)
}
var buf [10]byte
n, err := s.Read(buf[:])
if n != 0 || err == nil {
t.Fatalf("Read after Close returned (%v, %v), expected (%v, non-nil)", n, err, 0)
}
_, err = s.Write([]byte{1, 2, 3})
// Here we break the abstraction a little and look for a specific error,
// io.ErrClosedPipe. This is because we know the Conn uses an io.Pipe
// internally.
if err != io.ErrClosedPipe {
t.Fatalf("Write after Close returned %v, expected %v", err, io.ErrClosedPipe)
}
}