Skip to content

Ignore write error when echoing close frame #110

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 24, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion ci/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ if [[ $CI ]]; then
pip install -qqq autobahntestsuite
fi

go test -race -coverprofile=ci/out/coverage.prof --vet=off -bench=. -coverpkg=./... ./...
go test -race -coverprofile=ci/out/coverage.prof --vet=off -bench=. -coverpkg=./... "$@" ./...
go tool cover -func=ci/out/coverage.prof

if [[ $CI ]]; then
Expand Down
21 changes: 16 additions & 5 deletions websocket.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,10 @@ type Conn struct {
closer io.Closer
client bool

closeOnce sync.Once
closeErr error
closed chan struct{}
closeOnce sync.Once
closeErrOnce sync.Once
closeErr error
closed chan struct{}

// writeMsgLock is acquired to write a data message.
writeMsgLock chan struct{}
Expand Down Expand Up @@ -115,11 +116,17 @@ func (c *Conn) Subprotocol() string {
return c.subprotocol
}

func (c *Conn) setCloseErr(err error) {
c.closeErrOnce.Do(func() {
c.closeErr = xerrors.Errorf("websocket closed: %w", err)
})
}

func (c *Conn) close(err error) {
c.closeOnce.Do(func() {
runtime.SetFinalizer(c, nil)

c.closeErr = xerrors.Errorf("websocket closed: %w", err)
c.setCloseErr(err)
close(c.closed)

// Have to close after c.closed is closed to ensure any goroutine that wakes up
Expand Down Expand Up @@ -304,7 +311,11 @@ func (c *Conn) handleControl(ctx context.Context, h header) error {
c.Close(StatusProtocolError, "received invalid close payload")
return xerrors.Errorf("received invalid close payload: %w", err)
}
c.writeClose(b, xerrors.Errorf("received close frame: %w", ce))
// This ensures the closeErr of the Conn is always the received CloseError
// in case the echo close frame write fails.
// See https://github.com/nhooyr/websocket/issues/109
c.setCloseErr(xerrors.Errorf("received close frame: %w", ce))
c.writeClose(b, nil)
return c.closeErr
default:
panic(fmt.Sprintf("websocket: unexpected control opcode: %#v", h))
Expand Down