Ver código fonte

Add IsUnexpectedCloseError

Gary Burd 10 anos atrás
pai
commit
615f23bc98
3 arquivos alterados com 76 adições e 4 exclusões
  1. 16 4
      conn.go
  2. 20 0
      conn_test.go
  3. 40 0
      example_test.go

+ 16 - 4
conn.go

@@ -115,6 +115,20 @@ func IsCloseError(err error, codes ...int) bool {
 	return false
 }
 
+// IsUnexpectedCloseError returns boolean indicating whether the error is a
+// *CloseError with a code not in the list of expected codes.
+func IsUnexpectedCloseError(err error, expectedCodes ...int) bool {
+	if e, ok := err.(*CloseError); ok {
+		for _, code := range expectedCodes {
+			if e.Code == code {
+				return false
+			}
+		}
+		return true
+	}
+	return false
+}
+
 var (
 	errWriteTimeout        = &netError{msg: "websocket: write timeout", timeout: true, temporary: true}
 	errUnexpectedEOF       = &CloseError{Code: CloseAbnormalClosure, Text: io.ErrUnexpectedEOF.Error()}
@@ -321,9 +335,6 @@ func (c *Conn) WriteControl(messageType int, data []byte, deadline time.Time) er
 //
 // There can be at most one open writer on a connection. NextWriter closes the
 // previous writer if the application has not already done so.
-//
-// The NextWriter method and the writers returned from the method cannot be
-// accessed by more than one goroutine at a time.
 func (c *Conn) NextWriter(messageType int) (io.WriteCloser, error) {
 	if c.writeErr != nil {
 		return nil, c.writeErr
@@ -708,7 +719,8 @@ func (c *Conn) handleProtocolError(message string) error {
 // the previous message if the application has not already consumed it.
 //
 // Errors returned from NextReader are permanent. If NextReader returns a
-// non-nil error, then all subsequent calls to NextReader will the same error.
+// non-nil error, then all subsequent calls to NextReader return the same
+// error.
 func (c *Conn) NextReader() (messageType int, r io.Reader, err error) {
 
 	c.readSeq++

+ 20 - 0
conn_test.go

@@ -291,3 +291,23 @@ func TestCloseError(t *testing.T) {
 		}
 	}
 }
+
+var unexpectedCloseErrorTests = []struct {
+	err   error
+	codes []int
+	ok    bool
+}{
+	{&CloseError{Code: CloseNormalClosure}, []int{CloseNormalClosure}, false},
+	{&CloseError{Code: CloseNormalClosure}, []int{CloseNoStatusReceived}, true},
+	{&CloseError{Code: CloseNormalClosure}, []int{CloseNoStatusReceived, CloseNormalClosure}, false},
+	{errors.New("hello"), []int{CloseNormalClosure}, false},
+}
+
+func TestUnexpectedCloseErrors(t *testing.T) {
+	for _, tt := range unexpectedCloseErrorTests {
+		ok := IsUnexpectedCloseError(tt.err, tt.codes...)
+		if ok != tt.ok {
+			t.Errorf("IsUnexpectedCloseError(%#v, %#v) returned %v, want %v", tt.err, tt.codes, ok, tt.ok)
+		}
+	}
+}

+ 40 - 0
example_test.go

@@ -0,0 +1,40 @@
+// Copyright 2015 The Gorilla WebSocket Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package websocket_test
+
+import (
+	"log"
+	"net/http"
+	"testing"
+
+	"github.com/gorilla/websocket"
+)
+
+// The websocket.IsUnexpectedCloseError function is useful for identifying
+// application and protocol errors.
+//
+// This server application works with a client application running in the
+// browser. The client application does not explicitly close the websocket. The
+// only expected close message from the client has the code
+// websocket.CloseGoingAway. All other other close messages are likely the
+// result of an application or protocol error and are logged to aid debugging.
+func ExampleIsUnexpectedCloseError(err error, c *websocket.Conn, req *http.Request) {
+	for {
+		messageType, p, err := c.ReadMessage()
+		if err != nil {
+			if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway) {
+				log.Println("error: %v, user-agent: %v", err, req.Header.Get("User-Agent"))
+			}
+			return
+		}
+		processMesage(messageType, p)
+	}
+}
+
+func processMesage(mt int, p []byte) {}
+
+// TestX prevents godoc from showing this entire file in the example. Remove
+// this function when a second example is added.
+func TestX(t *testing.T) {}