Skip to content

Commit 47f93df

Browse files
committed
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.
1 parent 02eec99 commit 47f93df

File tree

2 files changed

+32
-20
lines changed

2 files changed

+32
-20
lines changed

conn.go

+25-13
Original file line numberDiff line numberDiff line change
@@ -70,18 +70,30 @@ var (
7070
ErrReadLimit = errors.New("websocket: read limit exceeded")
7171
)
7272

73-
type websocketError struct {
73+
// netError satisfies the net Error interface.
74+
type netError struct {
7475
msg string
7576
temporary bool
7677
timeout bool
7778
}
7879

79-
func (e *websocketError) Error() string { return e.msg }
80-
func (e *websocketError) Temporary() bool { return e.temporary }
81-
func (e *websocketError) Timeout() bool { return e.timeout }
80+
func (e *netError) Error() string { return e.msg }
81+
func (e *netError) Temporary() bool { return e.temporary }
82+
func (e *netError) Timeout() bool { return e.timeout }
83+
84+
// closeError represents close frame.
85+
type closeError struct {
86+
code int
87+
text string
88+
}
89+
90+
func (e *closeError) Error() string {
91+
return "websocket: close " + strconv.Itoa(e.code) + " " + e.text
92+
}
8293

8394
var (
84-
errWriteTimeout = &websocketError{msg: "websocket: write timeout", timeout: true}
95+
errWriteTimeout = &netError{msg: "websocket: write timeout", timeout: true}
96+
errUnexpectedEOF = &closeError{code: CloseAbnormalClosure, text: io.ErrUnexpectedEOF.Error()}
8597
errBadWriteOpCode = errors.New("websocket: bad write message type")
8698
errWriteClosed = errors.New("websocket: write closed")
8799
errInvalidControlFrame = errors.New("websocket: invalid control frame")
@@ -527,7 +539,7 @@ func (c *Conn) readFull(p []byte) (err error) {
527539
if n == len(p) {
528540
err = nil
529541
} else if err == io.EOF {
530-
err = io.ErrUnexpectedEOF
542+
err = errUnexpectedEOF
531543
}
532544
return
533545
}
@@ -649,17 +661,17 @@ func (c *Conn) advanceFrame() (int, error) {
649661
}
650662
case CloseMessage:
651663
c.WriteControl(CloseMessage, []byte{}, time.Now().Add(writeWait))
652-
if len(payload) < 2 {
653-
return noFrame, io.EOF
664+
closeCode := CloseNoStatusReceived
665+
closeText := ""
666+
if len(payload) >= 2 {
667+
closeCode = int(binary.BigEndian.Uint16(payload))
668+
closeText = string(payload[2:])
654669
}
655-
closeCode := binary.BigEndian.Uint16(payload)
656670
switch closeCode {
657671
case CloseNormalClosure, CloseGoingAway:
658672
return noFrame, io.EOF
659673
default:
660-
return noFrame, errors.New("websocket: close " +
661-
strconv.Itoa(int(closeCode)) + " " +
662-
string(payload[2:]))
674+
return noFrame, &closeError{code: closeCode, text: closeText}
663675
}
664676
}
665677

@@ -739,7 +751,7 @@ func (r messageReader) Read(b []byte) (int, error) {
739751

740752
err := r.c.readErr
741753
if err == io.EOF && r.seq == r.c.readSeq {
742-
err = io.ErrUnexpectedEOF
754+
err = errUnexpectedEOF
743755
}
744756
return 0, err
745757
}

conn_test.go

+7-7
Original file line numberDiff line numberDiff line change
@@ -152,16 +152,16 @@ func TestCloseBeforeFinalFrame(t *testing.T) {
152152

153153
w, _ := wc.NextWriter(BinaryMessage)
154154
w.Write(make([]byte, bufSize+bufSize/2))
155-
wc.WriteControl(CloseMessage, []byte{}, time.Now().Add(10*time.Second))
155+
wc.WriteControl(CloseMessage, FormatCloseMessage(CloseNormalClosure, ""), time.Now().Add(10*time.Second))
156156
w.Close()
157157

158158
op, r, err := rc.NextReader()
159159
if op != BinaryMessage || err != nil {
160160
t.Fatalf("NextReader() returned %d, %v", op, err)
161161
}
162162
_, err = io.Copy(ioutil.Discard, r)
163-
if err != io.ErrUnexpectedEOF {
164-
t.Fatalf("io.Copy() returned %v, want %v", err, io.ErrUnexpectedEOF)
163+
if err != errUnexpectedEOF {
164+
t.Fatalf("io.Copy() returned %v, want %v", err, errUnexpectedEOF)
165165
}
166166
_, _, err = rc.NextReader()
167167
if err != io.EOF {
@@ -184,12 +184,12 @@ func TestEOFBeforeFinalFrame(t *testing.T) {
184184
t.Fatalf("NextReader() returned %d, %v", op, err)
185185
}
186186
_, err = io.Copy(ioutil.Discard, r)
187-
if err != io.ErrUnexpectedEOF {
188-
t.Fatalf("io.Copy() returned %v, want %v", err, io.ErrUnexpectedEOF)
187+
if err != errUnexpectedEOF {
188+
t.Fatalf("io.Copy() returned %v, want %v", err, errUnexpectedEOF)
189189
}
190190
_, _, err = rc.NextReader()
191-
if err != io.ErrUnexpectedEOF {
192-
t.Fatalf("NextReader() returned %v, want %v", err, io.ErrUnexpectedEOF)
191+
if err != errUnexpectedEOF {
192+
t.Fatalf("NextReader() returned %v, want %v", err, errUnexpectedEOF)
193193
}
194194
}
195195

0 commit comments

Comments
 (0)