diff --git a/README.md b/README.md
index 9ca3ca8..9ad75a0 100644
--- a/README.md
+++ b/README.md
@@ -30,8 +30,8 @@ subdirectory](https://github.com/gorilla/websocket/tree/master/examples/autobahn
|
-gorilla |
-go.net |
+github.com/gorilla |
+golang.org/x/net |
RFC 6455 Features |
@@ -50,10 +50,10 @@ Notes:
1. Large messages are fragmented in [Chrome's new WebSocket implementation](http://www.ietf.org/mail-archive/web/hybi/current/msg10503.html).
2. The application can get the type of a received data message by implementing
- a [Codec marshal](http://godoc.org/code.google.com/p/go.net/websocket#Codec.Marshal)
+ a [Codec marshal](http://godoc.org/golang.org/x/net/websocket#Codec.Marshal)
function.
3. The go.net io.Reader and io.Writer operate across WebSocket frame boundaries.
Read returns when the input buffer is full or a frame boundary is
- encountered, Each call to Write sends a single frame message. The Gorilla
+ encountered. Each call to Write sends a single frame message. The Gorilla
io.Reader and io.WriteCloser operate on a single WebSocket message.
diff --git a/client.go b/client.go
index 3b5cac4..c25d24f 100644
--- a/client.go
+++ b/client.go
@@ -215,16 +215,6 @@ func (d *Dialer) Dial(urlStr string, requestHeader http.Header) (*Conn, *http.Re
}
}
- readBufferSize := d.ReadBufferSize
- if readBufferSize == 0 {
- readBufferSize = 4096
- }
-
- writeBufferSize := d.WriteBufferSize
- if writeBufferSize == 0 {
- writeBufferSize = 4096
- }
-
if len(d.Subprotocols) > 0 {
h := http.Header{}
for k, v := range requestHeader {
@@ -234,7 +224,7 @@ func (d *Dialer) Dial(urlStr string, requestHeader http.Header) (*Conn, *http.Re
requestHeader = h
}
- conn, resp, err := NewClient(netConn, u, requestHeader, readBufferSize, writeBufferSize)
+ conn, resp, err := NewClient(netConn, u, requestHeader, d.ReadBufferSize, d.WriteBufferSize)
if err != nil {
return nil, resp, err
}
diff --git a/conn.go b/conn.go
index 2701142..86c35e5 100644
--- a/conn.go
+++ b/conn.go
@@ -16,6 +16,20 @@ import (
"time"
)
+const (
+ maxFrameHeaderSize = 2 + 8 + 4 // Fixed header + length + mask
+ maxControlFramePayloadSize = 125
+ finalBit = 1 << 7
+ maskBit = 1 << 7
+ writeWait = time.Second
+
+ defaultReadBufferSize = 4096
+ defaultWriteBufferSize = 4096
+
+ continuationFrame = 0
+ noFrame = -1
+)
+
// Close codes defined in RFC 6455, section 11.7.
const (
CloseNormalClosure = 1000
@@ -55,49 +69,46 @@ const (
PongMessage = 10
)
-var (
- continuationFrame = 0
- noFrame = -1
-)
+// ErrCloseSent is returned when the application writes a message to the
+// connection after sending a close message.
+var ErrCloseSent = errors.New("websocket: close sent")
-var (
- // ErrCloseSent is returned when the application writes a message to the
- // connection after sending a close message.
- ErrCloseSent = errors.New("websocket: close sent")
+// ErrReadLimit is returned when reading a message that is larger than the
+// read limit set for the connection.
+var ErrReadLimit = errors.New("websocket: read limit exceeded")
- // ErrReadLimit is returned when reading a message that is larger than the
- // read limit set for the connection.
- 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")
)
-const (
- maxFrameHeaderSize = 2 + 8 + 4 // Fixed header + length + mask
- maxControlFramePayloadSize = 125
- finalBit = 1 << 7
- maskBit = 1 << 7
- writeWait = time.Second
-)
-
func hideTempErr(err error) error {
if e, ok := err.(net.Error); ok && e.Temporary() {
- err = struct{ error }{err}
+ err = &netError{msg: e.Error(), timeout: e.Timeout()}
}
return err
}
@@ -155,17 +166,24 @@ type Conn struct {
handlePing func(string) error
}
-func newConn(conn net.Conn, isServer bool, readBufSize, writeBufSize int) *Conn {
+func newConn(conn net.Conn, isServer bool, readBufferSize, writeBufferSize int) *Conn {
mu := make(chan bool, 1)
mu <- true
+ if readBufferSize == 0 {
+ readBufferSize = defaultReadBufferSize
+ }
+ if writeBufferSize == 0 {
+ writeBufferSize = defaultWriteBufferSize
+ }
+
c := &Conn{
isServer: isServer,
- br: bufio.NewReaderSize(conn, readBufSize),
+ br: bufio.NewReaderSize(conn, readBufferSize),
conn: conn,
mu: mu,
readFinal: true,
- writeBuf: make([]byte, writeBufSize+maxFrameHeaderSize),
+ writeBuf: make([]byte, writeBufferSize+maxFrameHeaderSize),
writeFrameType: noFrame,
writePos: maxFrameHeaderSize,
}
@@ -508,7 +526,7 @@ func (c *Conn) WriteMessage(messageType int, data []byte) error {
// SetWriteDeadline sets the write deadline on the underlying network
// connection. After a write has timed out, the websocket state is corrupt and
// all future writes will return an error. A zero value for t means writes will
-// not time out
+// not time out.
func (c *Conn) SetWriteDeadline(t time.Time) error {
c.writeDeadline = t
return nil
@@ -527,7 +545,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 +667,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 +757,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
}
diff --git a/conn_test.go b/conn_test.go
index 632725a..1f1197e 100644
--- a/conn_test.go
+++ b/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)
}
}
diff --git a/doc.go b/doc.go
index efde3dc..0d2bd91 100644
--- a/doc.go
+++ b/doc.go
@@ -97,10 +97,13 @@
//
// Concurrency
//
-// A Conn supports a single concurrent caller to the write methods (NextWriter,
-// SetWriteDeadline, WriteMessage) and a single concurrent caller to the read
-// methods (NextReader, SetReadDeadline, ReadMessage). The Close and
-// WriteControl methods can be called concurrently with all other methods.
+// Connections do not support concurrent calls to the write methods
+// (NextWriter, SetWriteDeadline, WriteMessage) or concurrent calls to the read
+// methods methods (NextReader, SetReadDeadline, ReadMessage). Connections do
+// support a concurrent reader and writer.
+//
+// The Close and WriteControl methods can be called concurrently with all other
+// methods.
//
// Read is Required
//
@@ -117,4 +120,29 @@
// }
// }
// }
+//
+// Origin Considerations
+//
+// Web browsers allow Javascript applications to open a WebSocket connection to
+// any host. It's up to the server to enforce an origin policy using the Origin
+// request header sent by the browser.
+//
+// The Upgrader calls the function specified in the CheckOrigin field to check
+// the origin. If the CheckOrigin function returns false, then the Upgrade
+// method fails the WebSocket handshake with HTTP status 403.
+//
+// If the CheckOrigin field is nil, then the Upgrader uses a safe default: fail
+// the handshake if the Origin request header is present and not equal to the
+// Host request header.
+//
+// An application can allow connections from any origin by specifying a
+// function that always returns true:
+//
+// var upgrader = websocket.Upgrader{
+// CheckOrigin: func(r *http.Request) bool { return true },
+// }
+//
+// The deprecated Upgrade function does not enforce an origin policy. It's the
+// application's responsibility to check the Origin header before calling
+// Upgrade.
package websocket
diff --git a/server.go b/server.go
index aae9b68..01e8899 100644
--- a/server.go
+++ b/server.go
@@ -21,11 +21,6 @@ type HandshakeError struct {
func (e HandshakeError) Error() string { return e.message }
-const (
- defaultReadBufferSize = 4096
- defaultWriteBufferSize = 4096
-)
-
// Upgrader specifies parameters for upgrading an HTTP connection to a
// WebSocket connection.
type Upgrader struct {
@@ -147,15 +142,7 @@ func (u *Upgrader) Upgrade(w http.ResponseWriter, r *http.Request, responseHeade
return nil, errors.New("websocket: client sent data before handshake is complete")
}
- readBufSize := u.ReadBufferSize
- if readBufSize == 0 {
- readBufSize = defaultReadBufferSize
- }
- writeBufSize := u.WriteBufferSize
- if writeBufSize == 0 {
- writeBufSize = defaultWriteBufferSize
- }
- c := newConn(netConn, true, readBufSize, writeBufSize)
+ c := newConn(netConn, true, u.ReadBufferSize, u.WriteBufferSize)
c.subprotocol = subprotocol
p := c.writeBuf[:0]