Cleanup remnants of net.Error Temporary()

A previous change to the package removed calls to the deprecated
net.Error Temporary() method. This change removes the cruft left behind
by that change.

- Delete the hideTempError function. Because applications should not
  call net.Error Temporary() method, there's no need to force the
  Temporary() return value to false. 

- Replace the internal errWriteTimeout error with the standard
  os.ErrDeadlineExceeded.

- Prior to the removing the calls to Temporary(), the default ping and
  close handlers ignored timeout errors by checking for net.Error
  Temporary() == true. The current code does not ignore timeout errors.
  Update the handlers to ignore timeout errors by checking for
  os.ErrDeadlineExceeded.

Unrelated to the above: Reduce noise in the test output by ignoring the
error from the compress/flate reader Close method.
This commit is contained in:
Halo Arrow 2023-08-29 11:00:25 -07:00
parent 666c197fc9
commit 620e1809ce
2 changed files with 24 additions and 34 deletions

56
conn.go
View File

@ -12,6 +12,7 @@ import (
"io" "io"
"log" "log"
"net" "net"
"os"
"strconv" "strconv"
"strings" "strings"
"sync" "sync"
@ -90,17 +91,6 @@ var ErrCloseSent = errors.New("websocket: close sent")
// read limit set for the connection. // read limit set for the connection.
var ErrReadLimit = errors.New("websocket: read limit exceeded") var ErrReadLimit = errors.New("websocket: read limit exceeded")
// netError satisfies the net Error interface.
type netError struct {
msg string
temporary bool
timeout bool
}
func (e *netError) Error() string { return e.msg }
func (e *netError) Temporary() bool { return e.temporary }
func (e *netError) Timeout() bool { return e.timeout }
// CloseError represents a close message. // CloseError represents a close message.
type CloseError struct { type CloseError struct {
// Code is defined in RFC 6455, section 11.7. // Code is defined in RFC 6455, section 11.7.
@ -174,7 +164,6 @@ func IsUnexpectedCloseError(err error, expectedCodes ...int) bool {
} }
var ( var (
errWriteTimeout = &netError{msg: "websocket: write timeout", timeout: true, temporary: true}
errUnexpectedEOF = &CloseError{Code: CloseAbnormalClosure, Text: io.ErrUnexpectedEOF.Error()} errUnexpectedEOF = &CloseError{Code: CloseAbnormalClosure, Text: io.ErrUnexpectedEOF.Error()}
errBadWriteOpCode = errors.New("websocket: bad write message type") errBadWriteOpCode = errors.New("websocket: bad write message type")
errWriteClosed = errors.New("websocket: write closed") errWriteClosed = errors.New("websocket: write closed")
@ -193,13 +182,6 @@ func newMaskKey() [4]byte {
return k return k
} }
func hideTempErr(err error) error {
if e, ok := err.(net.Error); ok {
err = &netError{msg: e.Error(), timeout: e.Timeout()}
}
return err
}
func isControl(frameType int) bool { func isControl(frameType int) bool {
return frameType == CloseMessage || frameType == PingMessage || frameType == PongMessage return frameType == CloseMessage || frameType == PingMessage || frameType == PongMessage
} }
@ -365,7 +347,6 @@ func (c *Conn) RemoteAddr() net.Addr {
// Write methods // Write methods
func (c *Conn) writeFatal(err error) error { func (c *Conn) writeFatal(err error) error {
err = hideTempErr(err)
c.writeErrMu.Lock() c.writeErrMu.Lock()
if c.writeErr == nil { if c.writeErr == nil {
c.writeErr = err c.writeErr = err
@ -451,7 +432,7 @@ func (c *Conn) WriteControl(messageType int, data []byte, deadline time.Time) er
if !deadline.IsZero() { if !deadline.IsZero() {
d = time.Until(deadline) d = time.Until(deadline)
if d < 0 { if d < 0 {
return errWriteTimeout return os.ErrDeadlineExceeded
} }
} }
@ -460,7 +441,7 @@ func (c *Conn) WriteControl(messageType int, data []byte, deadline time.Time) er
case <-c.mu: case <-c.mu:
timer.Stop() timer.Stop()
case <-timer.C: case <-timer.C:
return errWriteTimeout return os.ErrDeadlineExceeded
} }
defer func() { c.mu <- struct{}{} }() defer func() { c.mu <- struct{}{} }()
@ -1019,11 +1000,17 @@ func (c *Conn) handleProtocolError(message string) error {
// permanent. Once this method returns a non-nil error, all subsequent calls to // permanent. Once this method returns a non-nil error, all subsequent calls to
// this method return the same error. // this method return the same error.
func (c *Conn) NextReader() (messageType int, r io.Reader, err error) { func (c *Conn) NextReader() (messageType int, r io.Reader, err error) {
// Close previous reader, only relevant for decompression.
if c.reader != nil { if c.reader != nil {
if err := c.reader.Close(); err != nil { // In old versions of Go, the compress/flate reader Close method
log.Printf("websocket: discarding reader close error: %v", err) // released resources used by the reader. In recent versions of Go, the
} // Close method is a noop that returns the last Read error.
//
// We retain the call to Close because it's unclear from the
// documentation whether the call is required or not.
//
// We ignore the error returned from Close because that error was
// handled elsewhere.
_ = c.reader.Close()
c.reader = nil c.reader = nil
} }
@ -1033,7 +1020,7 @@ func (c *Conn) NextReader() (messageType int, r io.Reader, err error) {
for c.readErr == nil { for c.readErr == nil {
frameType, err := c.advanceFrame() frameType, err := c.advanceFrame()
if err != nil { if err != nil {
c.readErr = hideTempErr(err) c.readErr = err
break break
} }
@ -1073,7 +1060,7 @@ func (r *messageReader) Read(b []byte) (int, error) {
b = b[:c.readRemaining] b = b[:c.readRemaining]
} }
n, err := c.br.Read(b) n, err := c.br.Read(b)
c.readErr = hideTempErr(err) c.readErr = err
if c.isServer { if c.isServer {
c.readMaskPos = maskBytes(c.readMaskKey, c.readMaskPos, b[:n]) c.readMaskPos = maskBytes(c.readMaskKey, c.readMaskPos, b[:n])
} }
@ -1096,7 +1083,7 @@ func (r *messageReader) Read(b []byte) (int, error) {
frameType, err := c.advanceFrame() frameType, err := c.advanceFrame()
switch { switch {
case err != nil: case err != nil:
c.readErr = hideTempErr(err) c.readErr = err
case frameType == TextMessage || frameType == BinaryMessage: case frameType == TextMessage || frameType == BinaryMessage:
c.readErr = errors.New("websocket: internal error, unexpected text or binary in Reader") c.readErr = errors.New("websocket: internal error, unexpected text or binary in Reader")
} }
@ -1164,6 +1151,11 @@ func (c *Conn) SetCloseHandler(h func(code int, text string) error) {
h = func(code int, text string) error { h = func(code int, text string) error {
message := FormatCloseMessage(code, "") message := FormatCloseMessage(code, "")
if err := c.WriteControl(CloseMessage, message, time.Now().Add(writeWait)); err != nil { if err := c.WriteControl(CloseMessage, message, time.Now().Add(writeWait)); err != nil {
if errors.Is(err, ErrCloseSent) || errors.Is(err, os.ErrDeadlineExceeded) {
// Ignore error caused by close arriving after the application
// sent a close message. Ignore deadline errors.
return nil
}
return err return err
} }
return nil return nil
@ -1188,9 +1180,9 @@ func (c *Conn) SetPingHandler(h func(appData string) error) {
if h == nil { if h == nil {
h = func(message string) error { h = func(message string) error {
err := c.WriteControl(PongMessage, []byte(message), time.Now().Add(writeWait)) err := c.WriteControl(PongMessage, []byte(message), time.Now().Add(writeWait))
if err == ErrCloseSent { if errors.Is(err, ErrCloseSent) || errors.Is(err, os.ErrDeadlineExceeded) {
return nil // Ignore error caused by ping arriving after the application
} else if _, ok := err.(net.Error); ok { // sent a close message. Ignore deadline errors.
return nil return nil
} }
return err return err

View File

@ -18,8 +18,6 @@ import (
"time" "time"
) )
var _ net.Error = errWriteTimeout
type fakeNetConn struct { type fakeNetConn struct {
io.Reader io.Reader
io.Writer io.Writer