Merge branch 'master' of github.com:imkira/websocket into fixHeaderCase

This commit is contained in:
Mário Freitas 2014-11-17 20:08:31 +09:00
commit 9afdfba08c
6 changed files with 102 additions and 79 deletions

View File

@ -30,8 +30,8 @@ subdirectory](https://github.com/gorilla/websocket/tree/master/examples/autobahn
<table>
<tr>
<th></th>
<th><a href="http://godoc.org/github.com/gorilla/websocket">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/github.com/gorilla/websocket">github.com/gorilla</a></th>
<th><a href="http://godoc.org/golang.org/x/net/websocket">golang.org/x/net</a></th>
</tr>
<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).
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.

View File

@ -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
}

96
conn.go
View File

@ -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
}

View File

@ -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)
}
}

36
doc.go
View File

@ -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

View File

@ -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]