Browse Source

x/net/websocket: always close underlying connection on ws.Close

Fixes #10866

When ws.Close is called, always close the underlying ws.rwc.

Change-Id: Ia709d5e0bc51ffb7194668d2764848d012e0c652
Reviewed-on: https://go-review.googlesource.com/10135
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Dave Cheney 10 years ago
parent
commit
bb64f4dc73
2 changed files with 40 additions and 1 deletions
  1. 2 1
      websocket/websocket.go
  2. 38 0
      websocket/websocket_test.go

+ 2 - 1
websocket/websocket.go

@@ -216,10 +216,11 @@ func (ws *Conn) Write(msg []byte) (n int, err error) {
 // Close implements the io.Closer interface.
 func (ws *Conn) Close() error {
 	err := ws.frameHandler.WriteClose(ws.defaultCloseStatus)
+	err1 := ws.rwc.Close()
 	if err != nil {
 		return err
 	}
-	return ws.rwc.Close()
+	return err1
 }
 
 func (ws *Conn) IsClientConn() bool { return ws.request == nil }

+ 38 - 0
websocket/websocket_test.go

@@ -16,6 +16,7 @@ import (
 	"strings"
 	"sync"
 	"testing"
+	"time"
 )
 
 var serverAddr string
@@ -412,3 +413,40 @@ func TestParseAuthority(t *testing.T) {
 		}
 	}
 }
+
+type closerConn struct {
+	net.Conn
+	closed int // count of the number of times Close was called
+}
+
+func (c *closerConn) Close() error {
+	c.closed++
+	return c.Conn.Close()
+}
+
+func TestClose(t *testing.T) {
+	once.Do(startServer)
+
+	conn, err := net.Dial("tcp", serverAddr)
+	if err != nil {
+		t.Fatal("dialing", err)
+	}
+
+	cc := closerConn{Conn: conn}
+
+	client, err := NewClient(newConfig(t, "/echo"), &cc)
+	if err != nil {
+		t.Fatalf("WebSocket handshake: %v", err)
+	}
+
+	// set the deadline to ten minutes ago, which will have expired by the time
+	// client.Close sends the close status frame.
+	conn.SetDeadline(time.Now().Add(-10 * time.Minute))
+
+	if err := client.Close(); err == nil {
+		t.Errorf("ws.Close(): expected error, got %v", err)
+	}
+	if cc.closed < 1 {
+		t.Fatalf("ws.Close(): expected underlying ws.rwc.Close to be called > 0 times, got: %v", cc.closed)
+	}
+}