浏览代码

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.
Gary Burd 11 年之前
父节点
当前提交
47f93dfaed
共有 2 个文件被更改,包括 32 次插入20 次删除
  1. 25 13
      conn.go
  2. 7 7
      conn_test.go

+ 25 - 13
conn.go

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

+ 7 - 7
conn_test.go

@@ -152,7 +152,7 @@ func TestCloseBeforeFinalFrame(t *testing.T) {
 
 	w, _ := wc.NextWriter(BinaryMessage)
 	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()
 
 	op, r, err := rc.NextReader()
@@ -160,8 +160,8 @@ func TestCloseBeforeFinalFrame(t *testing.T) {
 		t.Fatalf("NextReader() returned %d, %v", op, err)
 	}
 	_, err = io.Copy(ioutil.Discard, r)
-	if err != io.ErrUnexpectedEOF {
-		t.Fatalf("io.Copy() returned %v, want %v", err, io.ErrUnexpectedEOF)
+	if err != errUnexpectedEOF {
+		t.Fatalf("io.Copy() returned %v, want %v", err, errUnexpectedEOF)
 	}
 	_, _, err = rc.NextReader()
 	if err != io.EOF {
@@ -184,12 +184,12 @@ func TestEOFBeforeFinalFrame(t *testing.T) {
 		t.Fatalf("NextReader() returned %d, %v", op, err)
 	}
 	_, err = io.Copy(ioutil.Discard, r)
-	if err != io.ErrUnexpectedEOF {
-		t.Fatalf("io.Copy() returned %v, want %v", err, io.ErrUnexpectedEOF)
+	if err != errUnexpectedEOF {
+		t.Fatalf("io.Copy() returned %v, want %v", err, errUnexpectedEOF)
 	}
 	_, _, err = rc.NextReader()
-	if err != io.ErrUnexpectedEOF {
-		t.Fatalf("NextReader() returned %v, want %v", err, io.ErrUnexpectedEOF)
+	if err != errUnexpectedEOF {
+		t.Fatalf("NextReader() returned %v, want %v", err, errUnexpectedEOF)
 	}
 }