Improve errors.

- Use new closeError type for reporting close frames to the application.
- Use closeError with code 1006 when the peer closes connection without
  sending a close frame. The error io.ErrUnexpectedEOF was used
  previously. This change helps developers distinguish abnormal closure
  and an unexpected EOF in the JSON parser.
This commit is contained in:
Gary Burd 2014-10-31 14:52:20 -07:00
parent 02eec998da
commit 47f93dfaed
2 changed files with 32 additions and 20 deletions

38
conn.go
View File

@ -70,18 +70,30 @@ var (
ErrReadLimit = errors.New("websocket: read limit exceeded") ErrReadLimit = errors.New("websocket: read limit exceeded")
) )
type websocketError struct { // netError satisfies the net Error interface.
type netError struct {
msg string msg string
temporary bool temporary bool
timeout bool timeout bool
} }
func (e *websocketError) Error() string { return e.msg } func (e *netError) Error() string { return e.msg }
func (e *websocketError) Temporary() bool { return e.temporary } func (e *netError) Temporary() bool { return e.temporary }
func (e *websocketError) Timeout() bool { return e.timeout } func (e *netError) Timeout() bool { return e.timeout }
// closeError represents close frame.
type closeError struct {
code int
text string
}
func (e *closeError) Error() string {
return "websocket: close " + strconv.Itoa(e.code) + " " + e.text
}
var ( var (
errWriteTimeout = &websocketError{msg: "websocket: write timeout", timeout: true} errWriteTimeout = &netError{msg: "websocket: write timeout", timeout: true}
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")
errInvalidControlFrame = errors.New("websocket: invalid control frame") errInvalidControlFrame = errors.New("websocket: invalid control frame")
@ -527,7 +539,7 @@ func (c *Conn) readFull(p []byte) (err error) {
if n == len(p) { if n == len(p) {
err = nil err = nil
} else if err == io.EOF { } else if err == io.EOF {
err = io.ErrUnexpectedEOF err = errUnexpectedEOF
} }
return return
} }
@ -649,17 +661,17 @@ func (c *Conn) advanceFrame() (int, error) {
} }
case CloseMessage: case CloseMessage:
c.WriteControl(CloseMessage, []byte{}, time.Now().Add(writeWait)) c.WriteControl(CloseMessage, []byte{}, time.Now().Add(writeWait))
if len(payload) < 2 { closeCode := CloseNoStatusReceived
return noFrame, io.EOF closeText := ""
if len(payload) >= 2 {
closeCode = int(binary.BigEndian.Uint16(payload))
closeText = string(payload[2:])
} }
closeCode := binary.BigEndian.Uint16(payload)
switch closeCode { switch closeCode {
case CloseNormalClosure, CloseGoingAway: case CloseNormalClosure, CloseGoingAway:
return noFrame, io.EOF return noFrame, io.EOF
default: default:
return noFrame, errors.New("websocket: close " + return noFrame, &closeError{code: closeCode, text: closeText}
strconv.Itoa(int(closeCode)) + " " +
string(payload[2:]))
} }
} }
@ -739,7 +751,7 @@ func (r messageReader) Read(b []byte) (int, error) {
err := r.c.readErr err := r.c.readErr
if err == io.EOF && r.seq == r.c.readSeq { if err == io.EOF && r.seq == r.c.readSeq {
err = io.ErrUnexpectedEOF err = errUnexpectedEOF
} }
return 0, err return 0, err
} }

View File

@ -152,7 +152,7 @@ func TestCloseBeforeFinalFrame(t *testing.T) {
w, _ := wc.NextWriter(BinaryMessage) w, _ := wc.NextWriter(BinaryMessage)
w.Write(make([]byte, bufSize+bufSize/2)) w.Write(make([]byte, bufSize+bufSize/2))
wc.WriteControl(CloseMessage, []byte{}, time.Now().Add(10*time.Second)) wc.WriteControl(CloseMessage, FormatCloseMessage(CloseNormalClosure, ""), time.Now().Add(10*time.Second))
w.Close() w.Close()
op, r, err := rc.NextReader() op, r, err := rc.NextReader()
@ -160,8 +160,8 @@ func TestCloseBeforeFinalFrame(t *testing.T) {
t.Fatalf("NextReader() returned %d, %v", op, err) t.Fatalf("NextReader() returned %d, %v", op, err)
} }
_, err = io.Copy(ioutil.Discard, r) _, err = io.Copy(ioutil.Discard, r)
if err != io.ErrUnexpectedEOF { if err != errUnexpectedEOF {
t.Fatalf("io.Copy() returned %v, want %v", err, io.ErrUnexpectedEOF) t.Fatalf("io.Copy() returned %v, want %v", err, errUnexpectedEOF)
} }
_, _, err = rc.NextReader() _, _, err = rc.NextReader()
if err != io.EOF { if err != io.EOF {
@ -184,12 +184,12 @@ func TestEOFBeforeFinalFrame(t *testing.T) {
t.Fatalf("NextReader() returned %d, %v", op, err) t.Fatalf("NextReader() returned %d, %v", op, err)
} }
_, err = io.Copy(ioutil.Discard, r) _, err = io.Copy(ioutil.Discard, r)
if err != io.ErrUnexpectedEOF { if err != errUnexpectedEOF {
t.Fatalf("io.Copy() returned %v, want %v", err, io.ErrUnexpectedEOF) t.Fatalf("io.Copy() returned %v, want %v", err, errUnexpectedEOF)
} }
_, _, err = rc.NextReader() _, _, err = rc.NextReader()
if err != io.ErrUnexpectedEOF { if err != errUnexpectedEOF {
t.Fatalf("NextReader() returned %v, want %v", err, io.ErrUnexpectedEOF) t.Fatalf("NextReader() returned %v, want %v", err, errUnexpectedEOF)
} }
} }