@@ -41,9 +41,10 @@ type Conn struct {
41
41
closer io.Closer
42
42
client bool
43
43
44
- closeOnce sync.Once
45
- closeErr error
46
- closed chan struct {}
44
+ closeOnce sync.Once
45
+ closeErrOnce sync.Once
46
+ closeErr error
47
+ closed chan struct {}
47
48
48
49
// writeMsgLock is acquired to write a data message.
49
50
writeMsgLock chan struct {}
@@ -115,11 +116,17 @@ func (c *Conn) Subprotocol() string {
115
116
return c .subprotocol
116
117
}
117
118
119
+ func (c * Conn ) setCloseErr (err error ) {
120
+ c .closeErrOnce .Do (func () {
121
+ c .closeErr = xerrors .Errorf ("websocket closed: %w" , err )
122
+ })
123
+ }
124
+
118
125
func (c * Conn ) close (err error ) {
119
126
c .closeOnce .Do (func () {
120
127
runtime .SetFinalizer (c , nil )
121
128
122
- c .closeErr = xerrors . Errorf ( "websocket closed: %w" , err )
129
+ c .setCloseErr ( err )
123
130
close (c .closed )
124
131
125
132
// Have to close after c.closed is closed to ensure any goroutine that wakes up
@@ -304,7 +311,11 @@ func (c *Conn) handleControl(ctx context.Context, h header) error {
304
311
c .Close (StatusProtocolError , "received invalid close payload" )
305
312
return xerrors .Errorf ("received invalid close payload: %w" , err )
306
313
}
307
- c .writeClose (b , xerrors .Errorf ("received close frame: %w" , ce ))
314
+ // This ensures the closeErr of the Conn is always the received CloseError
315
+ // in case the echo close frame write fails.
316
+ // See https://github.com/nhooyr/websocket/issues/109
317
+ c .setCloseErr (xerrors .Errorf ("received close frame: %w" , ce ))
318
+ c .writeClose (b , nil )
308
319
return c .closeErr
309
320
default :
310
321
panic (fmt .Sprintf ("websocket: unexpected control opcode: %#v" , h ))
0 commit comments