mirror of https://github.com/gorilla/websocket.git
Merge branch 'master' of github.com:imkira/websocket into fixHeaderCase
This commit is contained in:
commit
9afdfba08c
|
@ -30,8 +30,8 @@ subdirectory](https://github.com/gorilla/websocket/tree/master/examples/autobahn
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
<th></th>
|
<th></th>
|
||||||
<th><a href="http://godoc.org/github.com/gorilla/websocket">gorilla</a></th>
|
<th><a href="http://godoc.org/github.com/gorilla/websocket">github.com/gorilla</a></th>
|
||||||
<th><a href="http://godoc.org/code.google.com/p/go.net/websocket">go.net</a></th>
|
<th><a href="http://godoc.org/golang.org/x/net/websocket">golang.org/x/net</a></th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<tr><td colspan="3"><a href="http://tools.ietf.org/html/rfc6455">RFC 6455</a> Features</td></tr>
|
<tr><td colspan="3"><a href="http://tools.ietf.org/html/rfc6455">RFC 6455</a> Features</td></tr>
|
||||||
|
@ -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).
|
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
|
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.
|
function.
|
||||||
3. The go.net io.Reader and io.Writer operate across WebSocket frame boundaries.
|
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
|
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.
|
io.Reader and io.WriteCloser operate on a single WebSocket message.
|
||||||
|
|
||||||
|
|
12
client.go
12
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 {
|
if len(d.Subprotocols) > 0 {
|
||||||
h := http.Header{}
|
h := http.Header{}
|
||||||
for k, v := range requestHeader {
|
for k, v := range requestHeader {
|
||||||
|
@ -234,7 +224,7 @@ func (d *Dialer) Dial(urlStr string, requestHeader http.Header) (*Conn, *http.Re
|
||||||
requestHeader = h
|
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 {
|
if err != nil {
|
||||||
return nil, resp, err
|
return nil, resp, err
|
||||||
}
|
}
|
||||||
|
|
96
conn.go
96
conn.go
|
@ -16,6 +16,20 @@ import (
|
||||||
"time"
|
"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.
|
// Close codes defined in RFC 6455, section 11.7.
|
||||||
const (
|
const (
|
||||||
CloseNormalClosure = 1000
|
CloseNormalClosure = 1000
|
||||||
|
@ -55,49 +69,46 @@ const (
|
||||||
PongMessage = 10
|
PongMessage = 10
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
// ErrCloseSent is returned when the application writes a message to the
|
||||||
continuationFrame = 0
|
// connection after sending a close message.
|
||||||
noFrame = -1
|
var ErrCloseSent = errors.New("websocket: close sent")
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
// ErrReadLimit is returned when reading a message that is larger than the
|
||||||
// ErrCloseSent is returned when the application writes a message to the
|
// read limit set for the connection.
|
||||||
// connection after sending a close message.
|
var ErrReadLimit = errors.New("websocket: read limit exceeded")
|
||||||
ErrCloseSent = errors.New("websocket: close sent")
|
|
||||||
|
|
||||||
// ErrReadLimit is returned when reading a message that is larger than the
|
// netError satisfies the net Error interface.
|
||||||
// read limit set for the connection.
|
type netError struct {
|
||||||
ErrReadLimit = errors.New("websocket: read limit exceeded")
|
|
||||||
)
|
|
||||||
|
|
||||||
type websocketError struct {
|
|
||||||
msg string
|
msg string
|
||||||
temporary bool
|
temporary bool
|
||||||
timeout bool
|
timeout bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *websocketError) Error() string { return e.msg }
|
func (e *netError) Error() string { return e.msg }
|
||||||
func (e *websocketError) Temporary() bool { return e.temporary }
|
func (e *netError) Temporary() bool { return e.temporary }
|
||||||
func (e *websocketError) Timeout() bool { return e.timeout }
|
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 (
|
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")
|
errBadWriteOpCode = errors.New("websocket: bad write message type")
|
||||||
errWriteClosed = errors.New("websocket: write closed")
|
errWriteClosed = errors.New("websocket: write closed")
|
||||||
errInvalidControlFrame = errors.New("websocket: invalid control frame")
|
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 {
|
func hideTempErr(err error) error {
|
||||||
if e, ok := err.(net.Error); ok && e.Temporary() {
|
if e, ok := err.(net.Error); ok && e.Temporary() {
|
||||||
err = struct{ error }{err}
|
err = &netError{msg: e.Error(), timeout: e.Timeout()}
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -155,17 +166,24 @@ type Conn struct {
|
||||||
handlePing func(string) error
|
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 := make(chan bool, 1)
|
||||||
mu <- true
|
mu <- true
|
||||||
|
|
||||||
|
if readBufferSize == 0 {
|
||||||
|
readBufferSize = defaultReadBufferSize
|
||||||
|
}
|
||||||
|
if writeBufferSize == 0 {
|
||||||
|
writeBufferSize = defaultWriteBufferSize
|
||||||
|
}
|
||||||
|
|
||||||
c := &Conn{
|
c := &Conn{
|
||||||
isServer: isServer,
|
isServer: isServer,
|
||||||
br: bufio.NewReaderSize(conn, readBufSize),
|
br: bufio.NewReaderSize(conn, readBufferSize),
|
||||||
conn: conn,
|
conn: conn,
|
||||||
mu: mu,
|
mu: mu,
|
||||||
readFinal: true,
|
readFinal: true,
|
||||||
writeBuf: make([]byte, writeBufSize+maxFrameHeaderSize),
|
writeBuf: make([]byte, writeBufferSize+maxFrameHeaderSize),
|
||||||
writeFrameType: noFrame,
|
writeFrameType: noFrame,
|
||||||
writePos: maxFrameHeaderSize,
|
writePos: maxFrameHeaderSize,
|
||||||
}
|
}
|
||||||
|
@ -508,7 +526,7 @@ func (c *Conn) WriteMessage(messageType int, data []byte) error {
|
||||||
// SetWriteDeadline sets the write deadline on the underlying network
|
// SetWriteDeadline sets the write deadline on the underlying network
|
||||||
// connection. After a write has timed out, the websocket state is corrupt and
|
// 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
|
// 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 {
|
func (c *Conn) SetWriteDeadline(t time.Time) error {
|
||||||
c.writeDeadline = t
|
c.writeDeadline = t
|
||||||
return nil
|
return nil
|
||||||
|
@ -527,7 +545,7 @@ func (c *Conn) readFull(p []byte) (err error) {
|
||||||
if n == len(p) {
|
if n == len(p) {
|
||||||
err = nil
|
err = nil
|
||||||
} else if err == io.EOF {
|
} else if err == io.EOF {
|
||||||
err = io.ErrUnexpectedEOF
|
err = errUnexpectedEOF
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -649,17 +667,17 @@ func (c *Conn) advanceFrame() (int, error) {
|
||||||
}
|
}
|
||||||
case CloseMessage:
|
case CloseMessage:
|
||||||
c.WriteControl(CloseMessage, []byte{}, time.Now().Add(writeWait))
|
c.WriteControl(CloseMessage, []byte{}, time.Now().Add(writeWait))
|
||||||
if len(payload) < 2 {
|
closeCode := CloseNoStatusReceived
|
||||||
return noFrame, io.EOF
|
closeText := ""
|
||||||
|
if len(payload) >= 2 {
|
||||||
|
closeCode = int(binary.BigEndian.Uint16(payload))
|
||||||
|
closeText = string(payload[2:])
|
||||||
}
|
}
|
||||||
closeCode := binary.BigEndian.Uint16(payload)
|
|
||||||
switch closeCode {
|
switch closeCode {
|
||||||
case CloseNormalClosure, CloseGoingAway:
|
case CloseNormalClosure, CloseGoingAway:
|
||||||
return noFrame, io.EOF
|
return noFrame, io.EOF
|
||||||
default:
|
default:
|
||||||
return noFrame, errors.New("websocket: close " +
|
return noFrame, &closeError{code: closeCode, text: closeText}
|
||||||
strconv.Itoa(int(closeCode)) + " " +
|
|
||||||
string(payload[2:]))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -739,7 +757,7 @@ func (r messageReader) Read(b []byte) (int, error) {
|
||||||
|
|
||||||
err := r.c.readErr
|
err := r.c.readErr
|
||||||
if err == io.EOF && r.seq == r.c.readSeq {
|
if err == io.EOF && r.seq == r.c.readSeq {
|
||||||
err = io.ErrUnexpectedEOF
|
err = errUnexpectedEOF
|
||||||
}
|
}
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
14
conn_test.go
14
conn_test.go
|
@ -152,7 +152,7 @@ func TestCloseBeforeFinalFrame(t *testing.T) {
|
||||||
|
|
||||||
w, _ := wc.NextWriter(BinaryMessage)
|
w, _ := wc.NextWriter(BinaryMessage)
|
||||||
w.Write(make([]byte, bufSize+bufSize/2))
|
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()
|
w.Close()
|
||||||
|
|
||||||
op, r, err := rc.NextReader()
|
op, r, err := rc.NextReader()
|
||||||
|
@ -160,8 +160,8 @@ func TestCloseBeforeFinalFrame(t *testing.T) {
|
||||||
t.Fatalf("NextReader() returned %d, %v", op, err)
|
t.Fatalf("NextReader() returned %d, %v", op, err)
|
||||||
}
|
}
|
||||||
_, err = io.Copy(ioutil.Discard, r)
|
_, err = io.Copy(ioutil.Discard, r)
|
||||||
if err != io.ErrUnexpectedEOF {
|
if err != errUnexpectedEOF {
|
||||||
t.Fatalf("io.Copy() returned %v, want %v", err, io.ErrUnexpectedEOF)
|
t.Fatalf("io.Copy() returned %v, want %v", err, errUnexpectedEOF)
|
||||||
}
|
}
|
||||||
_, _, err = rc.NextReader()
|
_, _, err = rc.NextReader()
|
||||||
if err != io.EOF {
|
if err != io.EOF {
|
||||||
|
@ -184,12 +184,12 @@ func TestEOFBeforeFinalFrame(t *testing.T) {
|
||||||
t.Fatalf("NextReader() returned %d, %v", op, err)
|
t.Fatalf("NextReader() returned %d, %v", op, err)
|
||||||
}
|
}
|
||||||
_, err = io.Copy(ioutil.Discard, r)
|
_, err = io.Copy(ioutil.Discard, r)
|
||||||
if err != io.ErrUnexpectedEOF {
|
if err != errUnexpectedEOF {
|
||||||
t.Fatalf("io.Copy() returned %v, want %v", err, io.ErrUnexpectedEOF)
|
t.Fatalf("io.Copy() returned %v, want %v", err, errUnexpectedEOF)
|
||||||
}
|
}
|
||||||
_, _, err = rc.NextReader()
|
_, _, err = rc.NextReader()
|
||||||
if err != io.ErrUnexpectedEOF {
|
if err != errUnexpectedEOF {
|
||||||
t.Fatalf("NextReader() returned %v, want %v", err, io.ErrUnexpectedEOF)
|
t.Fatalf("NextReader() returned %v, want %v", err, errUnexpectedEOF)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
36
doc.go
36
doc.go
|
@ -97,10 +97,13 @@
|
||||||
//
|
//
|
||||||
// Concurrency
|
// Concurrency
|
||||||
//
|
//
|
||||||
// A Conn supports a single concurrent caller to the write methods (NextWriter,
|
// Connections do not support concurrent calls to the write methods
|
||||||
// SetWriteDeadline, WriteMessage) and a single concurrent caller to the read
|
// (NextWriter, SetWriteDeadline, WriteMessage) or concurrent calls to the read
|
||||||
// methods (NextReader, SetReadDeadline, ReadMessage). The Close and
|
// methods methods (NextReader, SetReadDeadline, ReadMessage). Connections do
|
||||||
// WriteControl methods can be called concurrently with all other methods.
|
// support a concurrent reader and writer.
|
||||||
|
//
|
||||||
|
// The Close and WriteControl methods can be called concurrently with all other
|
||||||
|
// methods.
|
||||||
//
|
//
|
||||||
// Read is Required
|
// 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
|
package websocket
|
||||||
|
|
15
server.go
15
server.go
|
@ -21,11 +21,6 @@ type HandshakeError struct {
|
||||||
|
|
||||||
func (e HandshakeError) Error() string { return e.message }
|
func (e HandshakeError) Error() string { return e.message }
|
||||||
|
|
||||||
const (
|
|
||||||
defaultReadBufferSize = 4096
|
|
||||||
defaultWriteBufferSize = 4096
|
|
||||||
)
|
|
||||||
|
|
||||||
// Upgrader specifies parameters for upgrading an HTTP connection to a
|
// Upgrader specifies parameters for upgrading an HTTP connection to a
|
||||||
// WebSocket connection.
|
// WebSocket connection.
|
||||||
type Upgrader struct {
|
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")
|
return nil, errors.New("websocket: client sent data before handshake is complete")
|
||||||
}
|
}
|
||||||
|
|
||||||
readBufSize := u.ReadBufferSize
|
c := newConn(netConn, true, u.ReadBufferSize, u.WriteBufferSize)
|
||||||
if readBufSize == 0 {
|
|
||||||
readBufSize = defaultReadBufferSize
|
|
||||||
}
|
|
||||||
writeBufSize := u.WriteBufferSize
|
|
||||||
if writeBufSize == 0 {
|
|
||||||
writeBufSize = defaultWriteBufferSize
|
|
||||||
}
|
|
||||||
c := newConn(netConn, true, readBufSize, writeBufSize)
|
|
||||||
c.subprotocol = subprotocol
|
c.subprotocol = subprotocol
|
||||||
|
|
||||||
p := c.writeBuf[:0]
|
p := c.writeBuf[:0]
|
||||||
|
|
Loading…
Reference in New Issue