From a2d85bcbfc8bbfed695b4f3c5b57e8b89911a727 Mon Sep 17 00:00:00 2001 From: Gary Burd Date: Tue, 19 Jan 2016 09:20:21 -0800 Subject: [PATCH] Add IsCloseError, improve doc about errors --- conn.go | 17 +++++++++++++++-- conn_test.go | 21 +++++++++++++++++++++ 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/conn.go b/conn.go index e8b6b3e..7afb796 100644 --- a/conn.go +++ b/conn.go @@ -102,6 +102,19 @@ func (e *CloseError) Error() string { return "websocket: close " + strconv.Itoa(e.Code) + " " + e.Text } +// IsCloseError returns boolean indicating whether the error is a *CloseError +// with one of the specified codes. +func IsCloseError(err error, codes ...int) bool { + if e, ok := err.(*CloseError); ok { + for _, code := range codes { + if e.Code == code { + return true + } + } + } + return false +} + var ( errWriteTimeout = &netError{msg: "websocket: write timeout", timeout: true, temporary: true} errUnexpectedEOF = &CloseError{Code: CloseAbnormalClosure, Text: io.ErrUnexpectedEOF.Error()} @@ -694,8 +707,8 @@ func (c *Conn) handleProtocolError(message string) error { // There can be at most one open reader on a connection. NextReader discards // the previous message if the application has not already consumed it. // -// The NextReader method and the readers returned from the method cannot be -// accessed by more than one goroutine at a time. +// Errors returned from NextReader are permanent. If NextReader returns a +// non-nil error, then all subsequent calls to NextReader will the same error. func (c *Conn) NextReader() (messageType int, r io.Reader, err error) { c.readSeq++ diff --git a/conn_test.go b/conn_test.go index 02f2d4b..62fc210 100644 --- a/conn_test.go +++ b/conn_test.go @@ -7,6 +7,7 @@ package websocket import ( "bufio" "bytes" + "errors" "fmt" "io" "io/ioutil" @@ -270,3 +271,23 @@ func TestBufioReadBytes(t *testing.T) { t.Fatalf("read returnd %d bytes, want %d bytes", len(p), len(m)) } } + +var closeErrorTests = []struct { + err error + codes []int + ok bool +}{ + {&CloseError{Code: CloseNormalClosure}, []int{CloseNormalClosure}, true}, + {&CloseError{Code: CloseNormalClosure}, []int{CloseNoStatusReceived}, false}, + {&CloseError{Code: CloseNormalClosure}, []int{CloseNoStatusReceived, CloseNormalClosure}, true}, + {errors.New("hello"), []int{CloseNormalClosure}, false}, +} + +func TestCloseError(t *testing.T) { + for _, tt := range closeErrorTests { + ok := IsCloseError(tt.err, tt.codes...) + if ok != tt.ok { + t.Errorf("IsCloseError(%#v, %#v) returned %v, want %v", tt.err, tt.codes, ok, tt.ok) + } + } +}