rpc/ws: switch to golang.org/x/net
code.google.com/p/go.net is deprecated and will cause problems in future versions of Go.
This commit is contained in:
		
							
								
								
									
										98
									
								
								Godeps/_workspace/src/code.google.com/p/go.net/websocket/client.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										98
									
								
								Godeps/_workspace/src/code.google.com/p/go.net/websocket/client.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,98 +0,0 @@
 | 
			
		||||
// Copyright 2009 The Go 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
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bufio"
 | 
			
		||||
	"crypto/tls"
 | 
			
		||||
	"io"
 | 
			
		||||
	"net"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"net/url"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// DialError is an error that occurs while dialling a websocket server.
 | 
			
		||||
type DialError struct {
 | 
			
		||||
	*Config
 | 
			
		||||
	Err error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (e *DialError) Error() string {
 | 
			
		||||
	return "websocket.Dial " + e.Config.Location.String() + ": " + e.Err.Error()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewConfig creates a new WebSocket config for client connection.
 | 
			
		||||
func NewConfig(server, origin string) (config *Config, err error) {
 | 
			
		||||
	config = new(Config)
 | 
			
		||||
	config.Version = ProtocolVersionHybi13
 | 
			
		||||
	config.Location, err = url.ParseRequestURI(server)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	config.Origin, err = url.ParseRequestURI(origin)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	config.Header = http.Header(make(map[string][]string))
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewClient creates a new WebSocket client connection over rwc.
 | 
			
		||||
func NewClient(config *Config, rwc io.ReadWriteCloser) (ws *Conn, err error) {
 | 
			
		||||
	br := bufio.NewReader(rwc)
 | 
			
		||||
	bw := bufio.NewWriter(rwc)
 | 
			
		||||
	err = hybiClientHandshake(config, br, bw)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	buf := bufio.NewReadWriter(br, bw)
 | 
			
		||||
	ws = newHybiClientConn(config, buf, rwc)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Dial opens a new client connection to a WebSocket.
 | 
			
		||||
func Dial(url_, protocol, origin string) (ws *Conn, err error) {
 | 
			
		||||
	config, err := NewConfig(url_, origin)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	if protocol != "" {
 | 
			
		||||
		config.Protocol = []string{protocol}
 | 
			
		||||
	}
 | 
			
		||||
	return DialConfig(config)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DialConfig opens a new client connection to a WebSocket with a config.
 | 
			
		||||
func DialConfig(config *Config) (ws *Conn, err error) {
 | 
			
		||||
	var client net.Conn
 | 
			
		||||
	if config.Location == nil {
 | 
			
		||||
		return nil, &DialError{config, ErrBadWebSocketLocation}
 | 
			
		||||
	}
 | 
			
		||||
	if config.Origin == nil {
 | 
			
		||||
		return nil, &DialError{config, ErrBadWebSocketOrigin}
 | 
			
		||||
	}
 | 
			
		||||
	switch config.Location.Scheme {
 | 
			
		||||
	case "ws":
 | 
			
		||||
		client, err = net.Dial("tcp", config.Location.Host)
 | 
			
		||||
 | 
			
		||||
	case "wss":
 | 
			
		||||
		client, err = tls.Dial("tcp", config.Location.Host, config.TlsConfig)
 | 
			
		||||
 | 
			
		||||
	default:
 | 
			
		||||
		err = ErrBadScheme
 | 
			
		||||
	}
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		goto Error
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ws, err = NewClient(config, client)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		goto Error
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
 | 
			
		||||
Error:
 | 
			
		||||
	return nil, &DialError{config, err}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										31
									
								
								Godeps/_workspace/src/code.google.com/p/go.net/websocket/exampledial_test.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										31
									
								
								Godeps/_workspace/src/code.google.com/p/go.net/websocket/exampledial_test.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,31 +0,0 @@
 | 
			
		||||
// Copyright 2012 The Go 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 (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"log"
 | 
			
		||||
 | 
			
		||||
	"code.google.com/p/go.net/websocket"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// This example demonstrates a trivial client.
 | 
			
		||||
func ExampleDial() {
 | 
			
		||||
	origin := "http://localhost/"
 | 
			
		||||
	url := "ws://localhost:12345/ws"
 | 
			
		||||
	ws, err := websocket.Dial(url, "", origin)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	if _, err := ws.Write([]byte("hello, world!\n")); err != nil {
 | 
			
		||||
		log.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	var msg = make([]byte, 512)
 | 
			
		||||
	var n int
 | 
			
		||||
	if n, err = ws.Read(msg); err != nil {
 | 
			
		||||
		log.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	fmt.Printf("Received: %s.\n", msg[:n])
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										26
									
								
								Godeps/_workspace/src/code.google.com/p/go.net/websocket/examplehandler_test.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										26
									
								
								Godeps/_workspace/src/code.google.com/p/go.net/websocket/examplehandler_test.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,26 +0,0 @@
 | 
			
		||||
// Copyright 2012 The Go 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 (
 | 
			
		||||
	"io"
 | 
			
		||||
	"net/http"
 | 
			
		||||
 | 
			
		||||
	"code.google.com/p/go.net/websocket"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Echo the data received on the WebSocket.
 | 
			
		||||
func EchoServer(ws *websocket.Conn) {
 | 
			
		||||
	io.Copy(ws, ws)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// This example demonstrates a trivial echo server.
 | 
			
		||||
func ExampleHandler() {
 | 
			
		||||
	http.Handle("/echo", websocket.Handler(EchoServer))
 | 
			
		||||
	err := http.ListenAndServe(":12345", nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		panic("ListenAndServe: " + err.Error())
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										564
									
								
								Godeps/_workspace/src/code.google.com/p/go.net/websocket/hybi.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										564
									
								
								Godeps/_workspace/src/code.google.com/p/go.net/websocket/hybi.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,564 +0,0 @@
 | 
			
		||||
// Copyright 2011 The Go 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
 | 
			
		||||
 | 
			
		||||
// This file implements a protocol of hybi draft.
 | 
			
		||||
// http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-17
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bufio"
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"crypto/rand"
 | 
			
		||||
	"crypto/sha1"
 | 
			
		||||
	"encoding/base64"
 | 
			
		||||
	"encoding/binary"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"net/url"
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	websocketGUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
 | 
			
		||||
 | 
			
		||||
	closeStatusNormal            = 1000
 | 
			
		||||
	closeStatusGoingAway         = 1001
 | 
			
		||||
	closeStatusProtocolError     = 1002
 | 
			
		||||
	closeStatusUnsupportedData   = 1003
 | 
			
		||||
	closeStatusFrameTooLarge     = 1004
 | 
			
		||||
	closeStatusNoStatusRcvd      = 1005
 | 
			
		||||
	closeStatusAbnormalClosure   = 1006
 | 
			
		||||
	closeStatusBadMessageData    = 1007
 | 
			
		||||
	closeStatusPolicyViolation   = 1008
 | 
			
		||||
	closeStatusTooBigData        = 1009
 | 
			
		||||
	closeStatusExtensionMismatch = 1010
 | 
			
		||||
 | 
			
		||||
	maxControlFramePayloadLength = 125
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	ErrBadMaskingKey         = &ProtocolError{"bad masking key"}
 | 
			
		||||
	ErrBadPongMessage        = &ProtocolError{"bad pong message"}
 | 
			
		||||
	ErrBadClosingStatus      = &ProtocolError{"bad closing status"}
 | 
			
		||||
	ErrUnsupportedExtensions = &ProtocolError{"unsupported extensions"}
 | 
			
		||||
	ErrNotImplemented        = &ProtocolError{"not implemented"}
 | 
			
		||||
 | 
			
		||||
	handshakeHeader = map[string]bool{
 | 
			
		||||
		"Host":                   true,
 | 
			
		||||
		"Upgrade":                true,
 | 
			
		||||
		"Connection":             true,
 | 
			
		||||
		"Sec-Websocket-Key":      true,
 | 
			
		||||
		"Sec-Websocket-Origin":   true,
 | 
			
		||||
		"Sec-Websocket-Version":  true,
 | 
			
		||||
		"Sec-Websocket-Protocol": true,
 | 
			
		||||
		"Sec-Websocket-Accept":   true,
 | 
			
		||||
	}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// A hybiFrameHeader is a frame header as defined in hybi draft.
 | 
			
		||||
type hybiFrameHeader struct {
 | 
			
		||||
	Fin        bool
 | 
			
		||||
	Rsv        [3]bool
 | 
			
		||||
	OpCode     byte
 | 
			
		||||
	Length     int64
 | 
			
		||||
	MaskingKey []byte
 | 
			
		||||
 | 
			
		||||
	data *bytes.Buffer
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// A hybiFrameReader is a reader for hybi frame.
 | 
			
		||||
type hybiFrameReader struct {
 | 
			
		||||
	reader io.Reader
 | 
			
		||||
 | 
			
		||||
	header hybiFrameHeader
 | 
			
		||||
	pos    int64
 | 
			
		||||
	length int
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (frame *hybiFrameReader) Read(msg []byte) (n int, err error) {
 | 
			
		||||
	n, err = frame.reader.Read(msg)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, err
 | 
			
		||||
	}
 | 
			
		||||
	if frame.header.MaskingKey != nil {
 | 
			
		||||
		for i := 0; i < n; i++ {
 | 
			
		||||
			msg[i] = msg[i] ^ frame.header.MaskingKey[frame.pos%4]
 | 
			
		||||
			frame.pos++
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return n, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (frame *hybiFrameReader) PayloadType() byte { return frame.header.OpCode }
 | 
			
		||||
 | 
			
		||||
func (frame *hybiFrameReader) HeaderReader() io.Reader {
 | 
			
		||||
	if frame.header.data == nil {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	if frame.header.data.Len() == 0 {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	return frame.header.data
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (frame *hybiFrameReader) TrailerReader() io.Reader { return nil }
 | 
			
		||||
 | 
			
		||||
func (frame *hybiFrameReader) Len() (n int) { return frame.length }
 | 
			
		||||
 | 
			
		||||
// A hybiFrameReaderFactory creates new frame reader based on its frame type.
 | 
			
		||||
type hybiFrameReaderFactory struct {
 | 
			
		||||
	*bufio.Reader
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewFrameReader reads a frame header from the connection, and creates new reader for the frame.
 | 
			
		||||
// See Section 5.2 Base Framing protocol for detail.
 | 
			
		||||
// http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-17#section-5.2
 | 
			
		||||
func (buf hybiFrameReaderFactory) NewFrameReader() (frame frameReader, err error) {
 | 
			
		||||
	hybiFrame := new(hybiFrameReader)
 | 
			
		||||
	frame = hybiFrame
 | 
			
		||||
	var header []byte
 | 
			
		||||
	var b byte
 | 
			
		||||
	// First byte. FIN/RSV1/RSV2/RSV3/OpCode(4bits)
 | 
			
		||||
	b, err = buf.ReadByte()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	header = append(header, b)
 | 
			
		||||
	hybiFrame.header.Fin = ((header[0] >> 7) & 1) != 0
 | 
			
		||||
	for i := 0; i < 3; i++ {
 | 
			
		||||
		j := uint(6 - i)
 | 
			
		||||
		hybiFrame.header.Rsv[i] = ((header[0] >> j) & 1) != 0
 | 
			
		||||
	}
 | 
			
		||||
	hybiFrame.header.OpCode = header[0] & 0x0f
 | 
			
		||||
 | 
			
		||||
	// Second byte. Mask/Payload len(7bits)
 | 
			
		||||
	b, err = buf.ReadByte()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	header = append(header, b)
 | 
			
		||||
	mask := (b & 0x80) != 0
 | 
			
		||||
	b &= 0x7f
 | 
			
		||||
	lengthFields := 0
 | 
			
		||||
	switch {
 | 
			
		||||
	case b <= 125: // Payload length 7bits.
 | 
			
		||||
		hybiFrame.header.Length = int64(b)
 | 
			
		||||
	case b == 126: // Payload length 7+16bits
 | 
			
		||||
		lengthFields = 2
 | 
			
		||||
	case b == 127: // Payload length 7+64bits
 | 
			
		||||
		lengthFields = 8
 | 
			
		||||
	}
 | 
			
		||||
	for i := 0; i < lengthFields; i++ {
 | 
			
		||||
		b, err = buf.ReadByte()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		header = append(header, b)
 | 
			
		||||
		hybiFrame.header.Length = hybiFrame.header.Length*256 + int64(b)
 | 
			
		||||
	}
 | 
			
		||||
	if mask {
 | 
			
		||||
		// Masking key. 4 bytes.
 | 
			
		||||
		for i := 0; i < 4; i++ {
 | 
			
		||||
			b, err = buf.ReadByte()
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
			header = append(header, b)
 | 
			
		||||
			hybiFrame.header.MaskingKey = append(hybiFrame.header.MaskingKey, b)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	hybiFrame.reader = io.LimitReader(buf.Reader, hybiFrame.header.Length)
 | 
			
		||||
	hybiFrame.header.data = bytes.NewBuffer(header)
 | 
			
		||||
	hybiFrame.length = len(header) + int(hybiFrame.header.Length)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// A HybiFrameWriter is a writer for hybi frame.
 | 
			
		||||
type hybiFrameWriter struct {
 | 
			
		||||
	writer *bufio.Writer
 | 
			
		||||
 | 
			
		||||
	header *hybiFrameHeader
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (frame *hybiFrameWriter) Write(msg []byte) (n int, err error) {
 | 
			
		||||
	var header []byte
 | 
			
		||||
	var b byte
 | 
			
		||||
	if frame.header.Fin {
 | 
			
		||||
		b |= 0x80
 | 
			
		||||
	}
 | 
			
		||||
	for i := 0; i < 3; i++ {
 | 
			
		||||
		if frame.header.Rsv[i] {
 | 
			
		||||
			j := uint(6 - i)
 | 
			
		||||
			b |= 1 << j
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	b |= frame.header.OpCode
 | 
			
		||||
	header = append(header, b)
 | 
			
		||||
	if frame.header.MaskingKey != nil {
 | 
			
		||||
		b = 0x80
 | 
			
		||||
	} else {
 | 
			
		||||
		b = 0
 | 
			
		||||
	}
 | 
			
		||||
	lengthFields := 0
 | 
			
		||||
	length := len(msg)
 | 
			
		||||
	switch {
 | 
			
		||||
	case length <= 125:
 | 
			
		||||
		b |= byte(length)
 | 
			
		||||
	case length < 65536:
 | 
			
		||||
		b |= 126
 | 
			
		||||
		lengthFields = 2
 | 
			
		||||
	default:
 | 
			
		||||
		b |= 127
 | 
			
		||||
		lengthFields = 8
 | 
			
		||||
	}
 | 
			
		||||
	header = append(header, b)
 | 
			
		||||
	for i := 0; i < lengthFields; i++ {
 | 
			
		||||
		j := uint((lengthFields - i - 1) * 8)
 | 
			
		||||
		b = byte((length >> j) & 0xff)
 | 
			
		||||
		header = append(header, b)
 | 
			
		||||
	}
 | 
			
		||||
	if frame.header.MaskingKey != nil {
 | 
			
		||||
		if len(frame.header.MaskingKey) != 4 {
 | 
			
		||||
			return 0, ErrBadMaskingKey
 | 
			
		||||
		}
 | 
			
		||||
		header = append(header, frame.header.MaskingKey...)
 | 
			
		||||
		frame.writer.Write(header)
 | 
			
		||||
		data := make([]byte, length)
 | 
			
		||||
		for i := range data {
 | 
			
		||||
			data[i] = msg[i] ^ frame.header.MaskingKey[i%4]
 | 
			
		||||
		}
 | 
			
		||||
		frame.writer.Write(data)
 | 
			
		||||
		err = frame.writer.Flush()
 | 
			
		||||
		return length, err
 | 
			
		||||
	}
 | 
			
		||||
	frame.writer.Write(header)
 | 
			
		||||
	frame.writer.Write(msg)
 | 
			
		||||
	err = frame.writer.Flush()
 | 
			
		||||
	return length, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (frame *hybiFrameWriter) Close() error { return nil }
 | 
			
		||||
 | 
			
		||||
type hybiFrameWriterFactory struct {
 | 
			
		||||
	*bufio.Writer
 | 
			
		||||
	needMaskingKey bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (buf hybiFrameWriterFactory) NewFrameWriter(payloadType byte) (frame frameWriter, err error) {
 | 
			
		||||
	frameHeader := &hybiFrameHeader{Fin: true, OpCode: payloadType}
 | 
			
		||||
	if buf.needMaskingKey {
 | 
			
		||||
		frameHeader.MaskingKey, err = generateMaskingKey()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return &hybiFrameWriter{writer: buf.Writer, header: frameHeader}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type hybiFrameHandler struct {
 | 
			
		||||
	conn        *Conn
 | 
			
		||||
	payloadType byte
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (handler *hybiFrameHandler) HandleFrame(frame frameReader) (r frameReader, err error) {
 | 
			
		||||
	if handler.conn.IsServerConn() {
 | 
			
		||||
		// The client MUST mask all frames sent to the server.
 | 
			
		||||
		if frame.(*hybiFrameReader).header.MaskingKey == nil {
 | 
			
		||||
			handler.WriteClose(closeStatusProtocolError)
 | 
			
		||||
			return nil, io.EOF
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		// The server MUST NOT mask all frames.
 | 
			
		||||
		if frame.(*hybiFrameReader).header.MaskingKey != nil {
 | 
			
		||||
			handler.WriteClose(closeStatusProtocolError)
 | 
			
		||||
			return nil, io.EOF
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if header := frame.HeaderReader(); header != nil {
 | 
			
		||||
		io.Copy(ioutil.Discard, header)
 | 
			
		||||
	}
 | 
			
		||||
	switch frame.PayloadType() {
 | 
			
		||||
	case ContinuationFrame:
 | 
			
		||||
		frame.(*hybiFrameReader).header.OpCode = handler.payloadType
 | 
			
		||||
	case TextFrame, BinaryFrame:
 | 
			
		||||
		handler.payloadType = frame.PayloadType()
 | 
			
		||||
	case CloseFrame:
 | 
			
		||||
		return nil, io.EOF
 | 
			
		||||
	case PingFrame:
 | 
			
		||||
		pingMsg := make([]byte, maxControlFramePayloadLength)
 | 
			
		||||
		n, err := io.ReadFull(frame, pingMsg)
 | 
			
		||||
		if err != nil && err != io.ErrUnexpectedEOF {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		io.Copy(ioutil.Discard, frame)
 | 
			
		||||
		n, err = handler.WritePong(pingMsg[:n])
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		return nil, nil
 | 
			
		||||
	case PongFrame:
 | 
			
		||||
		return nil, ErrNotImplemented
 | 
			
		||||
	}
 | 
			
		||||
	return frame, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (handler *hybiFrameHandler) WriteClose(status int) (err error) {
 | 
			
		||||
	handler.conn.wio.Lock()
 | 
			
		||||
	defer handler.conn.wio.Unlock()
 | 
			
		||||
	w, err := handler.conn.frameWriterFactory.NewFrameWriter(CloseFrame)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	msg := make([]byte, 2)
 | 
			
		||||
	binary.BigEndian.PutUint16(msg, uint16(status))
 | 
			
		||||
	_, err = w.Write(msg)
 | 
			
		||||
	w.Close()
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (handler *hybiFrameHandler) WritePong(msg []byte) (n int, err error) {
 | 
			
		||||
	handler.conn.wio.Lock()
 | 
			
		||||
	defer handler.conn.wio.Unlock()
 | 
			
		||||
	w, err := handler.conn.frameWriterFactory.NewFrameWriter(PongFrame)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, err
 | 
			
		||||
	}
 | 
			
		||||
	n, err = w.Write(msg)
 | 
			
		||||
	w.Close()
 | 
			
		||||
	return n, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// newHybiConn creates a new WebSocket connection speaking hybi draft protocol.
 | 
			
		||||
func newHybiConn(config *Config, buf *bufio.ReadWriter, rwc io.ReadWriteCloser, request *http.Request) *Conn {
 | 
			
		||||
	if buf == nil {
 | 
			
		||||
		br := bufio.NewReader(rwc)
 | 
			
		||||
		bw := bufio.NewWriter(rwc)
 | 
			
		||||
		buf = bufio.NewReadWriter(br, bw)
 | 
			
		||||
	}
 | 
			
		||||
	ws := &Conn{config: config, request: request, buf: buf, rwc: rwc,
 | 
			
		||||
		frameReaderFactory: hybiFrameReaderFactory{buf.Reader},
 | 
			
		||||
		frameWriterFactory: hybiFrameWriterFactory{
 | 
			
		||||
			buf.Writer, request == nil},
 | 
			
		||||
		PayloadType:        TextFrame,
 | 
			
		||||
		defaultCloseStatus: closeStatusNormal}
 | 
			
		||||
	ws.frameHandler = &hybiFrameHandler{conn: ws}
 | 
			
		||||
	return ws
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// generateMaskingKey generates a masking key for a frame.
 | 
			
		||||
func generateMaskingKey() (maskingKey []byte, err error) {
 | 
			
		||||
	maskingKey = make([]byte, 4)
 | 
			
		||||
	if _, err = io.ReadFull(rand.Reader, maskingKey); err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// generateNonce generates a nonce consisting of a randomly selected 16-byte
 | 
			
		||||
// value that has been base64-encoded.
 | 
			
		||||
func generateNonce() (nonce []byte) {
 | 
			
		||||
	key := make([]byte, 16)
 | 
			
		||||
	if _, err := io.ReadFull(rand.Reader, key); err != nil {
 | 
			
		||||
		panic(err)
 | 
			
		||||
	}
 | 
			
		||||
	nonce = make([]byte, 24)
 | 
			
		||||
	base64.StdEncoding.Encode(nonce, key)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// getNonceAccept computes the base64-encoded SHA-1 of the concatenation of
 | 
			
		||||
// the nonce ("Sec-WebSocket-Key" value) with the websocket GUID string.
 | 
			
		||||
func getNonceAccept(nonce []byte) (expected []byte, err error) {
 | 
			
		||||
	h := sha1.New()
 | 
			
		||||
	if _, err = h.Write(nonce); err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if _, err = h.Write([]byte(websocketGUID)); err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	expected = make([]byte, 28)
 | 
			
		||||
	base64.StdEncoding.Encode(expected, h.Sum(nil))
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Client handshake described in draft-ietf-hybi-thewebsocket-protocol-17
 | 
			
		||||
func hybiClientHandshake(config *Config, br *bufio.Reader, bw *bufio.Writer) (err error) {
 | 
			
		||||
	bw.WriteString("GET " + config.Location.RequestURI() + " HTTP/1.1\r\n")
 | 
			
		||||
 | 
			
		||||
	bw.WriteString("Host: " + config.Location.Host + "\r\n")
 | 
			
		||||
	bw.WriteString("Upgrade: websocket\r\n")
 | 
			
		||||
	bw.WriteString("Connection: Upgrade\r\n")
 | 
			
		||||
	nonce := generateNonce()
 | 
			
		||||
	if config.handshakeData != nil {
 | 
			
		||||
		nonce = []byte(config.handshakeData["key"])
 | 
			
		||||
	}
 | 
			
		||||
	bw.WriteString("Sec-WebSocket-Key: " + string(nonce) + "\r\n")
 | 
			
		||||
	bw.WriteString("Origin: " + strings.ToLower(config.Origin.String()) + "\r\n")
 | 
			
		||||
 | 
			
		||||
	if config.Version != ProtocolVersionHybi13 {
 | 
			
		||||
		return ErrBadProtocolVersion
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bw.WriteString("Sec-WebSocket-Version: " + fmt.Sprintf("%d", config.Version) + "\r\n")
 | 
			
		||||
	if len(config.Protocol) > 0 {
 | 
			
		||||
		bw.WriteString("Sec-WebSocket-Protocol: " + strings.Join(config.Protocol, ", ") + "\r\n")
 | 
			
		||||
	}
 | 
			
		||||
	// TODO(ukai): send Sec-WebSocket-Extensions.
 | 
			
		||||
	err = config.Header.WriteSubset(bw, handshakeHeader)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bw.WriteString("\r\n")
 | 
			
		||||
	if err = bw.Flush(); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	resp, err := http.ReadResponse(br, &http.Request{Method: "GET"})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if resp.StatusCode != 101 {
 | 
			
		||||
		return ErrBadStatus
 | 
			
		||||
	}
 | 
			
		||||
	if strings.ToLower(resp.Header.Get("Upgrade")) != "websocket" ||
 | 
			
		||||
		strings.ToLower(resp.Header.Get("Connection")) != "upgrade" {
 | 
			
		||||
		return ErrBadUpgrade
 | 
			
		||||
	}
 | 
			
		||||
	expectedAccept, err := getNonceAccept(nonce)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if resp.Header.Get("Sec-WebSocket-Accept") != string(expectedAccept) {
 | 
			
		||||
		return ErrChallengeResponse
 | 
			
		||||
	}
 | 
			
		||||
	if resp.Header.Get("Sec-WebSocket-Extensions") != "" {
 | 
			
		||||
		return ErrUnsupportedExtensions
 | 
			
		||||
	}
 | 
			
		||||
	offeredProtocol := resp.Header.Get("Sec-WebSocket-Protocol")
 | 
			
		||||
	if offeredProtocol != "" {
 | 
			
		||||
		protocolMatched := false
 | 
			
		||||
		for i := 0; i < len(config.Protocol); i++ {
 | 
			
		||||
			if config.Protocol[i] == offeredProtocol {
 | 
			
		||||
				protocolMatched = true
 | 
			
		||||
				break
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if !protocolMatched {
 | 
			
		||||
			return ErrBadWebSocketProtocol
 | 
			
		||||
		}
 | 
			
		||||
		config.Protocol = []string{offeredProtocol}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// newHybiClientConn creates a client WebSocket connection after handshake.
 | 
			
		||||
func newHybiClientConn(config *Config, buf *bufio.ReadWriter, rwc io.ReadWriteCloser) *Conn {
 | 
			
		||||
	return newHybiConn(config, buf, rwc, nil)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// A HybiServerHandshaker performs a server handshake using hybi draft protocol.
 | 
			
		||||
type hybiServerHandshaker struct {
 | 
			
		||||
	*Config
 | 
			
		||||
	accept []byte
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *hybiServerHandshaker) ReadHandshake(buf *bufio.Reader, req *http.Request) (code int, err error) {
 | 
			
		||||
	c.Version = ProtocolVersionHybi13
 | 
			
		||||
	if req.Method != "GET" {
 | 
			
		||||
		return http.StatusMethodNotAllowed, ErrBadRequestMethod
 | 
			
		||||
	}
 | 
			
		||||
	// HTTP version can be safely ignored.
 | 
			
		||||
 | 
			
		||||
	if strings.ToLower(req.Header.Get("Upgrade")) != "websocket" ||
 | 
			
		||||
		!strings.Contains(strings.ToLower(req.Header.Get("Connection")), "upgrade") {
 | 
			
		||||
		return http.StatusBadRequest, ErrNotWebSocket
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	key := req.Header.Get("Sec-Websocket-Key")
 | 
			
		||||
	if key == "" {
 | 
			
		||||
		return http.StatusBadRequest, ErrChallengeResponse
 | 
			
		||||
	}
 | 
			
		||||
	version := req.Header.Get("Sec-Websocket-Version")
 | 
			
		||||
	switch version {
 | 
			
		||||
	case "13":
 | 
			
		||||
		c.Version = ProtocolVersionHybi13
 | 
			
		||||
	default:
 | 
			
		||||
		return http.StatusBadRequest, ErrBadWebSocketVersion
 | 
			
		||||
	}
 | 
			
		||||
	var scheme string
 | 
			
		||||
	if req.TLS != nil {
 | 
			
		||||
		scheme = "wss"
 | 
			
		||||
	} else {
 | 
			
		||||
		scheme = "ws"
 | 
			
		||||
	}
 | 
			
		||||
	c.Location, err = url.ParseRequestURI(scheme + "://" + req.Host + req.URL.RequestURI())
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return http.StatusBadRequest, err
 | 
			
		||||
	}
 | 
			
		||||
	protocol := strings.TrimSpace(req.Header.Get("Sec-Websocket-Protocol"))
 | 
			
		||||
	if protocol != "" {
 | 
			
		||||
		protocols := strings.Split(protocol, ",")
 | 
			
		||||
		for i := 0; i < len(protocols); i++ {
 | 
			
		||||
			c.Protocol = append(c.Protocol, strings.TrimSpace(protocols[i]))
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	c.accept, err = getNonceAccept([]byte(key))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return http.StatusInternalServerError, err
 | 
			
		||||
	}
 | 
			
		||||
	return http.StatusSwitchingProtocols, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Origin parses Origin header in "req".
 | 
			
		||||
// If origin is "null", returns (nil, nil).
 | 
			
		||||
func Origin(config *Config, req *http.Request) (*url.URL, error) {
 | 
			
		||||
	var origin string
 | 
			
		||||
	switch config.Version {
 | 
			
		||||
	case ProtocolVersionHybi13:
 | 
			
		||||
		origin = req.Header.Get("Origin")
 | 
			
		||||
	}
 | 
			
		||||
	if origin == "null" {
 | 
			
		||||
		return nil, nil
 | 
			
		||||
	}
 | 
			
		||||
	return url.ParseRequestURI(origin)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *hybiServerHandshaker) AcceptHandshake(buf *bufio.Writer) (err error) {
 | 
			
		||||
	if len(c.Protocol) > 0 {
 | 
			
		||||
		if len(c.Protocol) != 1 {
 | 
			
		||||
			// You need choose a Protocol in Handshake func in Server.
 | 
			
		||||
			return ErrBadWebSocketProtocol
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	buf.WriteString("HTTP/1.1 101 Switching Protocols\r\n")
 | 
			
		||||
	buf.WriteString("Upgrade: websocket\r\n")
 | 
			
		||||
	buf.WriteString("Connection: Upgrade\r\n")
 | 
			
		||||
	buf.WriteString("Sec-WebSocket-Accept: " + string(c.accept) + "\r\n")
 | 
			
		||||
	if len(c.Protocol) > 0 {
 | 
			
		||||
		buf.WriteString("Sec-WebSocket-Protocol: " + c.Protocol[0] + "\r\n")
 | 
			
		||||
	}
 | 
			
		||||
	// TODO(ukai): send Sec-WebSocket-Extensions.
 | 
			
		||||
	if c.Header != nil {
 | 
			
		||||
		err := c.Header.WriteSubset(buf, handshakeHeader)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	buf.WriteString("\r\n")
 | 
			
		||||
	return buf.Flush()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *hybiServerHandshaker) NewServerConn(buf *bufio.ReadWriter, rwc io.ReadWriteCloser, request *http.Request) *Conn {
 | 
			
		||||
	return newHybiServerConn(c.Config, buf, rwc, request)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// newHybiServerConn returns a new WebSocket connection speaking hybi draft protocol.
 | 
			
		||||
func newHybiServerConn(config *Config, buf *bufio.ReadWriter, rwc io.ReadWriteCloser, request *http.Request) *Conn {
 | 
			
		||||
	return newHybiConn(config, buf, rwc, request)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										590
									
								
								Godeps/_workspace/src/code.google.com/p/go.net/websocket/hybi_test.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										590
									
								
								Godeps/_workspace/src/code.google.com/p/go.net/websocket/hybi_test.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,590 +0,0 @@
 | 
			
		||||
// Copyright 2011 The Go 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
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bufio"
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"net/url"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"testing"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Test the getNonceAccept function with values in
 | 
			
		||||
// http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-17
 | 
			
		||||
func TestSecWebSocketAccept(t *testing.T) {
 | 
			
		||||
	nonce := []byte("dGhlIHNhbXBsZSBub25jZQ==")
 | 
			
		||||
	expected := []byte("s3pPLMBiTxaQ9kYGzzhZRbK+xOo=")
 | 
			
		||||
	accept, err := getNonceAccept(nonce)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Errorf("getNonceAccept: returned error %v", err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if !bytes.Equal(expected, accept) {
 | 
			
		||||
		t.Errorf("getNonceAccept: expected %q got %q", expected, accept)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestHybiClientHandshake(t *testing.T) {
 | 
			
		||||
	b := bytes.NewBuffer([]byte{})
 | 
			
		||||
	bw := bufio.NewWriter(b)
 | 
			
		||||
	br := bufio.NewReader(strings.NewReader(`HTTP/1.1 101 Switching Protocols
 | 
			
		||||
Upgrade: websocket
 | 
			
		||||
Connection: Upgrade
 | 
			
		||||
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
 | 
			
		||||
Sec-WebSocket-Protocol: chat
 | 
			
		||||
 | 
			
		||||
`))
 | 
			
		||||
	var err error
 | 
			
		||||
	config := new(Config)
 | 
			
		||||
	config.Location, err = url.ParseRequestURI("ws://server.example.com/chat")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal("location url", err)
 | 
			
		||||
	}
 | 
			
		||||
	config.Origin, err = url.ParseRequestURI("http://example.com")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal("origin url", err)
 | 
			
		||||
	}
 | 
			
		||||
	config.Protocol = append(config.Protocol, "chat")
 | 
			
		||||
	config.Protocol = append(config.Protocol, "superchat")
 | 
			
		||||
	config.Version = ProtocolVersionHybi13
 | 
			
		||||
 | 
			
		||||
	config.handshakeData = map[string]string{
 | 
			
		||||
		"key": "dGhlIHNhbXBsZSBub25jZQ==",
 | 
			
		||||
	}
 | 
			
		||||
	err = hybiClientHandshake(config, br, bw)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Errorf("handshake failed: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	req, err := http.ReadRequest(bufio.NewReader(b))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatalf("read request: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	if req.Method != "GET" {
 | 
			
		||||
		t.Errorf("request method expected GET, but got %q", req.Method)
 | 
			
		||||
	}
 | 
			
		||||
	if req.URL.Path != "/chat" {
 | 
			
		||||
		t.Errorf("request path expected /chat, but got %q", req.URL.Path)
 | 
			
		||||
	}
 | 
			
		||||
	if req.Proto != "HTTP/1.1" {
 | 
			
		||||
		t.Errorf("request proto expected HTTP/1.1, but got %q", req.Proto)
 | 
			
		||||
	}
 | 
			
		||||
	if req.Host != "server.example.com" {
 | 
			
		||||
		t.Errorf("request Host expected server.example.com, but got %v", req.Host)
 | 
			
		||||
	}
 | 
			
		||||
	var expectedHeader = map[string]string{
 | 
			
		||||
		"Connection":             "Upgrade",
 | 
			
		||||
		"Upgrade":                "websocket",
 | 
			
		||||
		"Sec-Websocket-Key":      config.handshakeData["key"],
 | 
			
		||||
		"Origin":                 config.Origin.String(),
 | 
			
		||||
		"Sec-Websocket-Protocol": "chat, superchat",
 | 
			
		||||
		"Sec-Websocket-Version":  fmt.Sprintf("%d", ProtocolVersionHybi13),
 | 
			
		||||
	}
 | 
			
		||||
	for k, v := range expectedHeader {
 | 
			
		||||
		if req.Header.Get(k) != v {
 | 
			
		||||
			t.Errorf(fmt.Sprintf("%s expected %q but got %q", k, v, req.Header.Get(k)))
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestHybiClientHandshakeWithHeader(t *testing.T) {
 | 
			
		||||
	b := bytes.NewBuffer([]byte{})
 | 
			
		||||
	bw := bufio.NewWriter(b)
 | 
			
		||||
	br := bufio.NewReader(strings.NewReader(`HTTP/1.1 101 Switching Protocols
 | 
			
		||||
Upgrade: websocket
 | 
			
		||||
Connection: Upgrade
 | 
			
		||||
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
 | 
			
		||||
Sec-WebSocket-Protocol: chat
 | 
			
		||||
 | 
			
		||||
`))
 | 
			
		||||
	var err error
 | 
			
		||||
	config := new(Config)
 | 
			
		||||
	config.Location, err = url.ParseRequestURI("ws://server.example.com/chat")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal("location url", err)
 | 
			
		||||
	}
 | 
			
		||||
	config.Origin, err = url.ParseRequestURI("http://example.com")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal("origin url", err)
 | 
			
		||||
	}
 | 
			
		||||
	config.Protocol = append(config.Protocol, "chat")
 | 
			
		||||
	config.Protocol = append(config.Protocol, "superchat")
 | 
			
		||||
	config.Version = ProtocolVersionHybi13
 | 
			
		||||
	config.Header = http.Header(make(map[string][]string))
 | 
			
		||||
	config.Header.Add("User-Agent", "test")
 | 
			
		||||
 | 
			
		||||
	config.handshakeData = map[string]string{
 | 
			
		||||
		"key": "dGhlIHNhbXBsZSBub25jZQ==",
 | 
			
		||||
	}
 | 
			
		||||
	err = hybiClientHandshake(config, br, bw)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Errorf("handshake failed: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	req, err := http.ReadRequest(bufio.NewReader(b))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatalf("read request: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	if req.Method != "GET" {
 | 
			
		||||
		t.Errorf("request method expected GET, but got %q", req.Method)
 | 
			
		||||
	}
 | 
			
		||||
	if req.URL.Path != "/chat" {
 | 
			
		||||
		t.Errorf("request path expected /chat, but got %q", req.URL.Path)
 | 
			
		||||
	}
 | 
			
		||||
	if req.Proto != "HTTP/1.1" {
 | 
			
		||||
		t.Errorf("request proto expected HTTP/1.1, but got %q", req.Proto)
 | 
			
		||||
	}
 | 
			
		||||
	if req.Host != "server.example.com" {
 | 
			
		||||
		t.Errorf("request Host expected server.example.com, but got %v", req.Host)
 | 
			
		||||
	}
 | 
			
		||||
	var expectedHeader = map[string]string{
 | 
			
		||||
		"Connection":             "Upgrade",
 | 
			
		||||
		"Upgrade":                "websocket",
 | 
			
		||||
		"Sec-Websocket-Key":      config.handshakeData["key"],
 | 
			
		||||
		"Origin":                 config.Origin.String(),
 | 
			
		||||
		"Sec-Websocket-Protocol": "chat, superchat",
 | 
			
		||||
		"Sec-Websocket-Version":  fmt.Sprintf("%d", ProtocolVersionHybi13),
 | 
			
		||||
		"User-Agent":             "test",
 | 
			
		||||
	}
 | 
			
		||||
	for k, v := range expectedHeader {
 | 
			
		||||
		if req.Header.Get(k) != v {
 | 
			
		||||
			t.Errorf(fmt.Sprintf("%s expected %q but got %q", k, v, req.Header.Get(k)))
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestHybiServerHandshake(t *testing.T) {
 | 
			
		||||
	config := new(Config)
 | 
			
		||||
	handshaker := &hybiServerHandshaker{Config: config}
 | 
			
		||||
	br := bufio.NewReader(strings.NewReader(`GET /chat HTTP/1.1
 | 
			
		||||
Host: server.example.com
 | 
			
		||||
Upgrade: websocket
 | 
			
		||||
Connection: Upgrade
 | 
			
		||||
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
 | 
			
		||||
Origin: http://example.com
 | 
			
		||||
Sec-WebSocket-Protocol: chat, superchat
 | 
			
		||||
Sec-WebSocket-Version: 13
 | 
			
		||||
 | 
			
		||||
`))
 | 
			
		||||
	req, err := http.ReadRequest(br)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal("request", err)
 | 
			
		||||
	}
 | 
			
		||||
	code, err := handshaker.ReadHandshake(br, req)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Errorf("handshake failed: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	if code != http.StatusSwitchingProtocols {
 | 
			
		||||
		t.Errorf("status expected %q but got %q", http.StatusSwitchingProtocols, code)
 | 
			
		||||
	}
 | 
			
		||||
	expectedProtocols := []string{"chat", "superchat"}
 | 
			
		||||
	if fmt.Sprintf("%v", config.Protocol) != fmt.Sprintf("%v", expectedProtocols) {
 | 
			
		||||
		t.Errorf("protocol expected %q but got %q", expectedProtocols, config.Protocol)
 | 
			
		||||
	}
 | 
			
		||||
	b := bytes.NewBuffer([]byte{})
 | 
			
		||||
	bw := bufio.NewWriter(b)
 | 
			
		||||
 | 
			
		||||
	config.Protocol = config.Protocol[:1]
 | 
			
		||||
 | 
			
		||||
	err = handshaker.AcceptHandshake(bw)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Errorf("handshake response failed: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	expectedResponse := strings.Join([]string{
 | 
			
		||||
		"HTTP/1.1 101 Switching Protocols",
 | 
			
		||||
		"Upgrade: websocket",
 | 
			
		||||
		"Connection: Upgrade",
 | 
			
		||||
		"Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=",
 | 
			
		||||
		"Sec-WebSocket-Protocol: chat",
 | 
			
		||||
		"", ""}, "\r\n")
 | 
			
		||||
 | 
			
		||||
	if b.String() != expectedResponse {
 | 
			
		||||
		t.Errorf("handshake expected %q but got %q", expectedResponse, b.String())
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestHybiServerHandshakeNoSubProtocol(t *testing.T) {
 | 
			
		||||
	config := new(Config)
 | 
			
		||||
	handshaker := &hybiServerHandshaker{Config: config}
 | 
			
		||||
	br := bufio.NewReader(strings.NewReader(`GET /chat HTTP/1.1
 | 
			
		||||
Host: server.example.com
 | 
			
		||||
Upgrade: websocket
 | 
			
		||||
Connection: Upgrade
 | 
			
		||||
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
 | 
			
		||||
Origin: http://example.com
 | 
			
		||||
Sec-WebSocket-Version: 13
 | 
			
		||||
 | 
			
		||||
`))
 | 
			
		||||
	req, err := http.ReadRequest(br)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal("request", err)
 | 
			
		||||
	}
 | 
			
		||||
	code, err := handshaker.ReadHandshake(br, req)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Errorf("handshake failed: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	if code != http.StatusSwitchingProtocols {
 | 
			
		||||
		t.Errorf("status expected %q but got %q", http.StatusSwitchingProtocols, code)
 | 
			
		||||
	}
 | 
			
		||||
	if len(config.Protocol) != 0 {
 | 
			
		||||
		t.Errorf("len(config.Protocol) expected 0, but got %q", len(config.Protocol))
 | 
			
		||||
	}
 | 
			
		||||
	b := bytes.NewBuffer([]byte{})
 | 
			
		||||
	bw := bufio.NewWriter(b)
 | 
			
		||||
 | 
			
		||||
	err = handshaker.AcceptHandshake(bw)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Errorf("handshake response failed: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	expectedResponse := strings.Join([]string{
 | 
			
		||||
		"HTTP/1.1 101 Switching Protocols",
 | 
			
		||||
		"Upgrade: websocket",
 | 
			
		||||
		"Connection: Upgrade",
 | 
			
		||||
		"Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=",
 | 
			
		||||
		"", ""}, "\r\n")
 | 
			
		||||
 | 
			
		||||
	if b.String() != expectedResponse {
 | 
			
		||||
		t.Errorf("handshake expected %q but got %q", expectedResponse, b.String())
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestHybiServerHandshakeHybiBadVersion(t *testing.T) {
 | 
			
		||||
	config := new(Config)
 | 
			
		||||
	handshaker := &hybiServerHandshaker{Config: config}
 | 
			
		||||
	br := bufio.NewReader(strings.NewReader(`GET /chat HTTP/1.1
 | 
			
		||||
Host: server.example.com
 | 
			
		||||
Upgrade: websocket
 | 
			
		||||
Connection: Upgrade
 | 
			
		||||
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
 | 
			
		||||
Sec-WebSocket-Origin: http://example.com
 | 
			
		||||
Sec-WebSocket-Protocol: chat, superchat
 | 
			
		||||
Sec-WebSocket-Version: 9
 | 
			
		||||
 | 
			
		||||
`))
 | 
			
		||||
	req, err := http.ReadRequest(br)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal("request", err)
 | 
			
		||||
	}
 | 
			
		||||
	code, err := handshaker.ReadHandshake(br, req)
 | 
			
		||||
	if err != ErrBadWebSocketVersion {
 | 
			
		||||
		t.Errorf("handshake expected err %q but got %q", ErrBadWebSocketVersion, err)
 | 
			
		||||
	}
 | 
			
		||||
	if code != http.StatusBadRequest {
 | 
			
		||||
		t.Errorf("status expected %q but got %q", http.StatusBadRequest, code)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func testHybiFrame(t *testing.T, testHeader, testPayload, testMaskedPayload []byte, frameHeader *hybiFrameHeader) {
 | 
			
		||||
	b := bytes.NewBuffer([]byte{})
 | 
			
		||||
	frameWriterFactory := &hybiFrameWriterFactory{bufio.NewWriter(b), false}
 | 
			
		||||
	w, _ := frameWriterFactory.NewFrameWriter(TextFrame)
 | 
			
		||||
	w.(*hybiFrameWriter).header = frameHeader
 | 
			
		||||
	_, err := w.Write(testPayload)
 | 
			
		||||
	w.Close()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Errorf("Write error %q", err)
 | 
			
		||||
	}
 | 
			
		||||
	var expectedFrame []byte
 | 
			
		||||
	expectedFrame = append(expectedFrame, testHeader...)
 | 
			
		||||
	expectedFrame = append(expectedFrame, testMaskedPayload...)
 | 
			
		||||
	if !bytes.Equal(expectedFrame, b.Bytes()) {
 | 
			
		||||
		t.Errorf("frame expected %q got %q", expectedFrame, b.Bytes())
 | 
			
		||||
	}
 | 
			
		||||
	frameReaderFactory := &hybiFrameReaderFactory{bufio.NewReader(b)}
 | 
			
		||||
	r, err := frameReaderFactory.NewFrameReader()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Errorf("Read error %q", err)
 | 
			
		||||
	}
 | 
			
		||||
	if header := r.HeaderReader(); header == nil {
 | 
			
		||||
		t.Errorf("no header")
 | 
			
		||||
	} else {
 | 
			
		||||
		actualHeader := make([]byte, r.Len())
 | 
			
		||||
		n, err := header.Read(actualHeader)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			t.Errorf("Read header error %q", err)
 | 
			
		||||
		} else {
 | 
			
		||||
			if n < len(testHeader) {
 | 
			
		||||
				t.Errorf("header too short %q got %q", testHeader, actualHeader[:n])
 | 
			
		||||
			}
 | 
			
		||||
			if !bytes.Equal(testHeader, actualHeader[:n]) {
 | 
			
		||||
				t.Errorf("header expected %q got %q", testHeader, actualHeader[:n])
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if trailer := r.TrailerReader(); trailer != nil {
 | 
			
		||||
		t.Errorf("unexpected trailer %q", trailer)
 | 
			
		||||
	}
 | 
			
		||||
	frame := r.(*hybiFrameReader)
 | 
			
		||||
	if frameHeader.Fin != frame.header.Fin ||
 | 
			
		||||
		frameHeader.OpCode != frame.header.OpCode ||
 | 
			
		||||
		len(testPayload) != int(frame.header.Length) {
 | 
			
		||||
		t.Errorf("mismatch %v (%d) vs %v", frameHeader, len(testPayload), frame)
 | 
			
		||||
	}
 | 
			
		||||
	payload := make([]byte, len(testPayload))
 | 
			
		||||
	_, err = r.Read(payload)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Errorf("read %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	if !bytes.Equal(testPayload, payload) {
 | 
			
		||||
		t.Errorf("payload %q vs %q", testPayload, payload)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestHybiShortTextFrame(t *testing.T) {
 | 
			
		||||
	frameHeader := &hybiFrameHeader{Fin: true, OpCode: TextFrame}
 | 
			
		||||
	payload := []byte("hello")
 | 
			
		||||
	testHybiFrame(t, []byte{0x81, 0x05}, payload, payload, frameHeader)
 | 
			
		||||
 | 
			
		||||
	payload = make([]byte, 125)
 | 
			
		||||
	testHybiFrame(t, []byte{0x81, 125}, payload, payload, frameHeader)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestHybiShortMaskedTextFrame(t *testing.T) {
 | 
			
		||||
	frameHeader := &hybiFrameHeader{Fin: true, OpCode: TextFrame,
 | 
			
		||||
		MaskingKey: []byte{0xcc, 0x55, 0x80, 0x20}}
 | 
			
		||||
	payload := []byte("hello")
 | 
			
		||||
	maskedPayload := []byte{0xa4, 0x30, 0xec, 0x4c, 0xa3}
 | 
			
		||||
	header := []byte{0x81, 0x85}
 | 
			
		||||
	header = append(header, frameHeader.MaskingKey...)
 | 
			
		||||
	testHybiFrame(t, header, payload, maskedPayload, frameHeader)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestHybiShortBinaryFrame(t *testing.T) {
 | 
			
		||||
	frameHeader := &hybiFrameHeader{Fin: true, OpCode: BinaryFrame}
 | 
			
		||||
	payload := []byte("hello")
 | 
			
		||||
	testHybiFrame(t, []byte{0x82, 0x05}, payload, payload, frameHeader)
 | 
			
		||||
 | 
			
		||||
	payload = make([]byte, 125)
 | 
			
		||||
	testHybiFrame(t, []byte{0x82, 125}, payload, payload, frameHeader)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestHybiControlFrame(t *testing.T) {
 | 
			
		||||
	frameHeader := &hybiFrameHeader{Fin: true, OpCode: PingFrame}
 | 
			
		||||
	payload := []byte("hello")
 | 
			
		||||
	testHybiFrame(t, []byte{0x89, 0x05}, payload, payload, frameHeader)
 | 
			
		||||
 | 
			
		||||
	frameHeader = &hybiFrameHeader{Fin: true, OpCode: PongFrame}
 | 
			
		||||
	testHybiFrame(t, []byte{0x8A, 0x05}, payload, payload, frameHeader)
 | 
			
		||||
 | 
			
		||||
	frameHeader = &hybiFrameHeader{Fin: true, OpCode: CloseFrame}
 | 
			
		||||
	payload = []byte{0x03, 0xe8} // 1000
 | 
			
		||||
	testHybiFrame(t, []byte{0x88, 0x02}, payload, payload, frameHeader)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestHybiLongFrame(t *testing.T) {
 | 
			
		||||
	frameHeader := &hybiFrameHeader{Fin: true, OpCode: TextFrame}
 | 
			
		||||
	payload := make([]byte, 126)
 | 
			
		||||
	testHybiFrame(t, []byte{0x81, 126, 0x00, 126}, payload, payload, frameHeader)
 | 
			
		||||
 | 
			
		||||
	payload = make([]byte, 65535)
 | 
			
		||||
	testHybiFrame(t, []byte{0x81, 126, 0xff, 0xff}, payload, payload, frameHeader)
 | 
			
		||||
 | 
			
		||||
	payload = make([]byte, 65536)
 | 
			
		||||
	testHybiFrame(t, []byte{0x81, 127, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00}, payload, payload, frameHeader)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestHybiClientRead(t *testing.T) {
 | 
			
		||||
	wireData := []byte{0x81, 0x05, 'h', 'e', 'l', 'l', 'o',
 | 
			
		||||
		0x89, 0x05, 'h', 'e', 'l', 'l', 'o', // ping
 | 
			
		||||
		0x81, 0x05, 'w', 'o', 'r', 'l', 'd'}
 | 
			
		||||
	br := bufio.NewReader(bytes.NewBuffer(wireData))
 | 
			
		||||
	bw := bufio.NewWriter(bytes.NewBuffer([]byte{}))
 | 
			
		||||
	conn := newHybiConn(newConfig(t, "/"), bufio.NewReadWriter(br, bw), nil, nil)
 | 
			
		||||
 | 
			
		||||
	msg := make([]byte, 512)
 | 
			
		||||
	n, err := conn.Read(msg)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Errorf("read 1st frame, error %q", err)
 | 
			
		||||
	}
 | 
			
		||||
	if n != 5 {
 | 
			
		||||
		t.Errorf("read 1st frame, expect 5, got %d", n)
 | 
			
		||||
	}
 | 
			
		||||
	if !bytes.Equal(wireData[2:7], msg[:n]) {
 | 
			
		||||
		t.Errorf("read 1st frame %v, got %v", wireData[2:7], msg[:n])
 | 
			
		||||
	}
 | 
			
		||||
	n, err = conn.Read(msg)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Errorf("read 2nd frame, error %q", err)
 | 
			
		||||
	}
 | 
			
		||||
	if n != 5 {
 | 
			
		||||
		t.Errorf("read 2nd frame, expect 5, got %d", n)
 | 
			
		||||
	}
 | 
			
		||||
	if !bytes.Equal(wireData[16:21], msg[:n]) {
 | 
			
		||||
		t.Errorf("read 2nd frame %v, got %v", wireData[16:21], msg[:n])
 | 
			
		||||
	}
 | 
			
		||||
	n, err = conn.Read(msg)
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		t.Errorf("read not EOF")
 | 
			
		||||
	}
 | 
			
		||||
	if n != 0 {
 | 
			
		||||
		t.Errorf("expect read 0, got %d", n)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestHybiShortRead(t *testing.T) {
 | 
			
		||||
	wireData := []byte{0x81, 0x05, 'h', 'e', 'l', 'l', 'o',
 | 
			
		||||
		0x89, 0x05, 'h', 'e', 'l', 'l', 'o', // ping
 | 
			
		||||
		0x81, 0x05, 'w', 'o', 'r', 'l', 'd'}
 | 
			
		||||
	br := bufio.NewReader(bytes.NewBuffer(wireData))
 | 
			
		||||
	bw := bufio.NewWriter(bytes.NewBuffer([]byte{}))
 | 
			
		||||
	conn := newHybiConn(newConfig(t, "/"), bufio.NewReadWriter(br, bw), nil, nil)
 | 
			
		||||
 | 
			
		||||
	step := 0
 | 
			
		||||
	pos := 0
 | 
			
		||||
	expectedPos := []int{2, 5, 16, 19}
 | 
			
		||||
	expectedLen := []int{3, 2, 3, 2}
 | 
			
		||||
	for {
 | 
			
		||||
		msg := make([]byte, 3)
 | 
			
		||||
		n, err := conn.Read(msg)
 | 
			
		||||
		if step >= len(expectedPos) {
 | 
			
		||||
			if err == nil {
 | 
			
		||||
				t.Errorf("read not EOF")
 | 
			
		||||
			}
 | 
			
		||||
			if n != 0 {
 | 
			
		||||
				t.Errorf("expect read 0, got %d", n)
 | 
			
		||||
			}
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		pos = expectedPos[step]
 | 
			
		||||
		endPos := pos + expectedLen[step]
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			t.Errorf("read from %d, got error %q", pos, err)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		if n != endPos-pos {
 | 
			
		||||
			t.Errorf("read from %d, expect %d, got %d", pos, endPos-pos, n)
 | 
			
		||||
		}
 | 
			
		||||
		if !bytes.Equal(wireData[pos:endPos], msg[:n]) {
 | 
			
		||||
			t.Errorf("read from %d, frame %v, got %v", pos, wireData[pos:endPos], msg[:n])
 | 
			
		||||
		}
 | 
			
		||||
		step++
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestHybiServerRead(t *testing.T) {
 | 
			
		||||
	wireData := []byte{0x81, 0x85, 0xcc, 0x55, 0x80, 0x20,
 | 
			
		||||
		0xa4, 0x30, 0xec, 0x4c, 0xa3, // hello
 | 
			
		||||
		0x89, 0x85, 0xcc, 0x55, 0x80, 0x20,
 | 
			
		||||
		0xa4, 0x30, 0xec, 0x4c, 0xa3, // ping: hello
 | 
			
		||||
		0x81, 0x85, 0xed, 0x83, 0xb4, 0x24,
 | 
			
		||||
		0x9a, 0xec, 0xc6, 0x48, 0x89, // world
 | 
			
		||||
	}
 | 
			
		||||
	br := bufio.NewReader(bytes.NewBuffer(wireData))
 | 
			
		||||
	bw := bufio.NewWriter(bytes.NewBuffer([]byte{}))
 | 
			
		||||
	conn := newHybiConn(newConfig(t, "/"), bufio.NewReadWriter(br, bw), nil, new(http.Request))
 | 
			
		||||
 | 
			
		||||
	expected := [][]byte{[]byte("hello"), []byte("world")}
 | 
			
		||||
 | 
			
		||||
	msg := make([]byte, 512)
 | 
			
		||||
	n, err := conn.Read(msg)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Errorf("read 1st frame, error %q", err)
 | 
			
		||||
	}
 | 
			
		||||
	if n != 5 {
 | 
			
		||||
		t.Errorf("read 1st frame, expect 5, got %d", n)
 | 
			
		||||
	}
 | 
			
		||||
	if !bytes.Equal(expected[0], msg[:n]) {
 | 
			
		||||
		t.Errorf("read 1st frame %q, got %q", expected[0], msg[:n])
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	n, err = conn.Read(msg)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Errorf("read 2nd frame, error %q", err)
 | 
			
		||||
	}
 | 
			
		||||
	if n != 5 {
 | 
			
		||||
		t.Errorf("read 2nd frame, expect 5, got %d", n)
 | 
			
		||||
	}
 | 
			
		||||
	if !bytes.Equal(expected[1], msg[:n]) {
 | 
			
		||||
		t.Errorf("read 2nd frame %q, got %q", expected[1], msg[:n])
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	n, err = conn.Read(msg)
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		t.Errorf("read not EOF")
 | 
			
		||||
	}
 | 
			
		||||
	if n != 0 {
 | 
			
		||||
		t.Errorf("expect read 0, got %d", n)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestHybiServerReadWithoutMasking(t *testing.T) {
 | 
			
		||||
	wireData := []byte{0x81, 0x05, 'h', 'e', 'l', 'l', 'o'}
 | 
			
		||||
	br := bufio.NewReader(bytes.NewBuffer(wireData))
 | 
			
		||||
	bw := bufio.NewWriter(bytes.NewBuffer([]byte{}))
 | 
			
		||||
	conn := newHybiConn(newConfig(t, "/"), bufio.NewReadWriter(br, bw), nil, new(http.Request))
 | 
			
		||||
	// server MUST close the connection upon receiving a non-masked frame.
 | 
			
		||||
	msg := make([]byte, 512)
 | 
			
		||||
	_, err := conn.Read(msg)
 | 
			
		||||
	if err != io.EOF {
 | 
			
		||||
		t.Errorf("read 1st frame, expect %q, but got %q", io.EOF, err)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestHybiClientReadWithMasking(t *testing.T) {
 | 
			
		||||
	wireData := []byte{0x81, 0x85, 0xcc, 0x55, 0x80, 0x20,
 | 
			
		||||
		0xa4, 0x30, 0xec, 0x4c, 0xa3, // hello
 | 
			
		||||
	}
 | 
			
		||||
	br := bufio.NewReader(bytes.NewBuffer(wireData))
 | 
			
		||||
	bw := bufio.NewWriter(bytes.NewBuffer([]byte{}))
 | 
			
		||||
	conn := newHybiConn(newConfig(t, "/"), bufio.NewReadWriter(br, bw), nil, nil)
 | 
			
		||||
 | 
			
		||||
	// client MUST close the connection upon receiving a masked frame.
 | 
			
		||||
	msg := make([]byte, 512)
 | 
			
		||||
	_, err := conn.Read(msg)
 | 
			
		||||
	if err != io.EOF {
 | 
			
		||||
		t.Errorf("read 1st frame, expect %q, but got %q", io.EOF, err)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Test the hybiServerHandshaker supports firefox implementation and
 | 
			
		||||
// checks Connection request header include (but it's not necessary
 | 
			
		||||
// equal to) "upgrade"
 | 
			
		||||
func TestHybiServerFirefoxHandshake(t *testing.T) {
 | 
			
		||||
	config := new(Config)
 | 
			
		||||
	handshaker := &hybiServerHandshaker{Config: config}
 | 
			
		||||
	br := bufio.NewReader(strings.NewReader(`GET /chat HTTP/1.1
 | 
			
		||||
Host: server.example.com
 | 
			
		||||
Upgrade: websocket
 | 
			
		||||
Connection: keep-alive, upgrade
 | 
			
		||||
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
 | 
			
		||||
Origin: http://example.com
 | 
			
		||||
Sec-WebSocket-Protocol: chat, superchat
 | 
			
		||||
Sec-WebSocket-Version: 13
 | 
			
		||||
 | 
			
		||||
`))
 | 
			
		||||
	req, err := http.ReadRequest(br)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal("request", err)
 | 
			
		||||
	}
 | 
			
		||||
	code, err := handshaker.ReadHandshake(br, req)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Errorf("handshake failed: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	if code != http.StatusSwitchingProtocols {
 | 
			
		||||
		t.Errorf("status expected %q but got %q", http.StatusSwitchingProtocols, code)
 | 
			
		||||
	}
 | 
			
		||||
	b := bytes.NewBuffer([]byte{})
 | 
			
		||||
	bw := bufio.NewWriter(b)
 | 
			
		||||
 | 
			
		||||
	config.Protocol = []string{"chat"}
 | 
			
		||||
 | 
			
		||||
	err = handshaker.AcceptHandshake(bw)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Errorf("handshake response failed: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	expectedResponse := strings.Join([]string{
 | 
			
		||||
		"HTTP/1.1 101 Switching Protocols",
 | 
			
		||||
		"Upgrade: websocket",
 | 
			
		||||
		"Connection: Upgrade",
 | 
			
		||||
		"Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=",
 | 
			
		||||
		"Sec-WebSocket-Protocol: chat",
 | 
			
		||||
		"", ""}, "\r\n")
 | 
			
		||||
 | 
			
		||||
	if b.String() != expectedResponse {
 | 
			
		||||
		t.Errorf("handshake expected %q but got %q", expectedResponse, b.String())
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										114
									
								
								Godeps/_workspace/src/code.google.com/p/go.net/websocket/server.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										114
									
								
								Godeps/_workspace/src/code.google.com/p/go.net/websocket/server.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,114 +0,0 @@
 | 
			
		||||
// Copyright 2009 The Go 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
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bufio"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"net/http"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func newServerConn(rwc io.ReadWriteCloser, buf *bufio.ReadWriter, req *http.Request, config *Config, handshake func(*Config, *http.Request) error) (conn *Conn, err error) {
 | 
			
		||||
	var hs serverHandshaker = &hybiServerHandshaker{Config: config}
 | 
			
		||||
	code, err := hs.ReadHandshake(buf.Reader, req)
 | 
			
		||||
	if err == ErrBadWebSocketVersion {
 | 
			
		||||
		fmt.Fprintf(buf, "HTTP/1.1 %03d %s\r\n", code, http.StatusText(code))
 | 
			
		||||
		fmt.Fprintf(buf, "Sec-WebSocket-Version: %s\r\n", SupportedProtocolVersion)
 | 
			
		||||
		buf.WriteString("\r\n")
 | 
			
		||||
		buf.WriteString(err.Error())
 | 
			
		||||
		buf.Flush()
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		fmt.Fprintf(buf, "HTTP/1.1 %03d %s\r\n", code, http.StatusText(code))
 | 
			
		||||
		buf.WriteString("\r\n")
 | 
			
		||||
		buf.WriteString(err.Error())
 | 
			
		||||
		buf.Flush()
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if handshake != nil {
 | 
			
		||||
		err = handshake(config, req)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			code = http.StatusForbidden
 | 
			
		||||
			fmt.Fprintf(buf, "HTTP/1.1 %03d %s\r\n", code, http.StatusText(code))
 | 
			
		||||
			buf.WriteString("\r\n")
 | 
			
		||||
			buf.Flush()
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	err = hs.AcceptHandshake(buf.Writer)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		code = http.StatusBadRequest
 | 
			
		||||
		fmt.Fprintf(buf, "HTTP/1.1 %03d %s\r\n", code, http.StatusText(code))
 | 
			
		||||
		buf.WriteString("\r\n")
 | 
			
		||||
		buf.Flush()
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	conn = hs.NewServerConn(buf, rwc, req)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Server represents a server of a WebSocket.
 | 
			
		||||
type Server struct {
 | 
			
		||||
	// Config is a WebSocket configuration for new WebSocket connection.
 | 
			
		||||
	Config
 | 
			
		||||
 | 
			
		||||
	// Handshake is an optional function in WebSocket handshake.
 | 
			
		||||
	// For example, you can check, or don't check Origin header.
 | 
			
		||||
	// Another example, you can select config.Protocol.
 | 
			
		||||
	Handshake func(*Config, *http.Request) error
 | 
			
		||||
 | 
			
		||||
	// Handler handles a WebSocket connection.
 | 
			
		||||
	Handler
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ServeHTTP implements the http.Handler interface for a WebSocket
 | 
			
		||||
func (s Server) ServeHTTP(w http.ResponseWriter, req *http.Request) {
 | 
			
		||||
	s.serveWebSocket(w, req)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s Server) serveWebSocket(w http.ResponseWriter, req *http.Request) {
 | 
			
		||||
	rwc, buf, err := w.(http.Hijacker).Hijack()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		panic("Hijack failed: " + err.Error())
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	// The server should abort the WebSocket connection if it finds
 | 
			
		||||
	// the client did not send a handshake that matches with protocol
 | 
			
		||||
	// specification.
 | 
			
		||||
	defer rwc.Close()
 | 
			
		||||
	conn, err := newServerConn(rwc, buf, req, &s.Config, s.Handshake)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if conn == nil {
 | 
			
		||||
		panic("unexpected nil conn")
 | 
			
		||||
	}
 | 
			
		||||
	s.Handler(conn)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Handler is a simple interface to a WebSocket browser client.
 | 
			
		||||
// It checks if Origin header is valid URL by default.
 | 
			
		||||
// You might want to verify websocket.Conn.Config().Origin in the func.
 | 
			
		||||
// If you use Server instead of Handler, you could call websocket.Origin and
 | 
			
		||||
// check the origin in your Handshake func. So, if you want to accept
 | 
			
		||||
// non-browser client, which doesn't send Origin header, you could use Server
 | 
			
		||||
//. that doesn't check origin in its Handshake.
 | 
			
		||||
type Handler func(*Conn)
 | 
			
		||||
 | 
			
		||||
func checkOrigin(config *Config, req *http.Request) (err error) {
 | 
			
		||||
	config.Origin, err = Origin(config, req)
 | 
			
		||||
	if err == nil && config.Origin == nil {
 | 
			
		||||
		return fmt.Errorf("null origin")
 | 
			
		||||
	}
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ServeHTTP implements the http.Handler interface for a WebSocket
 | 
			
		||||
func (h Handler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
 | 
			
		||||
	s := Server{Handler: h, Handshake: checkOrigin}
 | 
			
		||||
	s.serveWebSocket(w, req)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										411
									
								
								Godeps/_workspace/src/code.google.com/p/go.net/websocket/websocket.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										411
									
								
								Godeps/_workspace/src/code.google.com/p/go.net/websocket/websocket.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,411 +0,0 @@
 | 
			
		||||
// Copyright 2009 The Go 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 implements a client and server for the WebSocket protocol
 | 
			
		||||
// as specified in RFC 6455.
 | 
			
		||||
package websocket
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bufio"
 | 
			
		||||
	"crypto/tls"
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"io"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"net"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"net/url"
 | 
			
		||||
	"sync"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	ProtocolVersionHybi13    = 13
 | 
			
		||||
	ProtocolVersionHybi      = ProtocolVersionHybi13
 | 
			
		||||
	SupportedProtocolVersion = "13"
 | 
			
		||||
 | 
			
		||||
	ContinuationFrame = 0
 | 
			
		||||
	TextFrame         = 1
 | 
			
		||||
	BinaryFrame       = 2
 | 
			
		||||
	CloseFrame        = 8
 | 
			
		||||
	PingFrame         = 9
 | 
			
		||||
	PongFrame         = 10
 | 
			
		||||
	UnknownFrame      = 255
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// ProtocolError represents WebSocket protocol errors.
 | 
			
		||||
type ProtocolError struct {
 | 
			
		||||
	ErrorString string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (err *ProtocolError) Error() string { return err.ErrorString }
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	ErrBadProtocolVersion   = &ProtocolError{"bad protocol version"}
 | 
			
		||||
	ErrBadScheme            = &ProtocolError{"bad scheme"}
 | 
			
		||||
	ErrBadStatus            = &ProtocolError{"bad status"}
 | 
			
		||||
	ErrBadUpgrade           = &ProtocolError{"missing or bad upgrade"}
 | 
			
		||||
	ErrBadWebSocketOrigin   = &ProtocolError{"missing or bad WebSocket-Origin"}
 | 
			
		||||
	ErrBadWebSocketLocation = &ProtocolError{"missing or bad WebSocket-Location"}
 | 
			
		||||
	ErrBadWebSocketProtocol = &ProtocolError{"missing or bad WebSocket-Protocol"}
 | 
			
		||||
	ErrBadWebSocketVersion  = &ProtocolError{"missing or bad WebSocket Version"}
 | 
			
		||||
	ErrChallengeResponse    = &ProtocolError{"mismatch challenge/response"}
 | 
			
		||||
	ErrBadFrame             = &ProtocolError{"bad frame"}
 | 
			
		||||
	ErrBadFrameBoundary     = &ProtocolError{"not on frame boundary"}
 | 
			
		||||
	ErrNotWebSocket         = &ProtocolError{"not websocket protocol"}
 | 
			
		||||
	ErrBadRequestMethod     = &ProtocolError{"bad method"}
 | 
			
		||||
	ErrNotSupported         = &ProtocolError{"not supported"}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Addr is an implementation of net.Addr for WebSocket.
 | 
			
		||||
type Addr struct {
 | 
			
		||||
	*url.URL
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Network returns the network type for a WebSocket, "websocket".
 | 
			
		||||
func (addr *Addr) Network() string { return "websocket" }
 | 
			
		||||
 | 
			
		||||
// Config is a WebSocket configuration
 | 
			
		||||
type Config struct {
 | 
			
		||||
	// A WebSocket server address.
 | 
			
		||||
	Location *url.URL
 | 
			
		||||
 | 
			
		||||
	// A Websocket client origin.
 | 
			
		||||
	Origin *url.URL
 | 
			
		||||
 | 
			
		||||
	// WebSocket subprotocols.
 | 
			
		||||
	Protocol []string
 | 
			
		||||
 | 
			
		||||
	// WebSocket protocol version.
 | 
			
		||||
	Version int
 | 
			
		||||
 | 
			
		||||
	// TLS config for secure WebSocket (wss).
 | 
			
		||||
	TlsConfig *tls.Config
 | 
			
		||||
 | 
			
		||||
	// Additional header fields to be sent in WebSocket opening handshake.
 | 
			
		||||
	Header http.Header
 | 
			
		||||
 | 
			
		||||
	handshakeData map[string]string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// serverHandshaker is an interface to handle WebSocket server side handshake.
 | 
			
		||||
type serverHandshaker interface {
 | 
			
		||||
	// ReadHandshake reads handshake request message from client.
 | 
			
		||||
	// Returns http response code and error if any.
 | 
			
		||||
	ReadHandshake(buf *bufio.Reader, req *http.Request) (code int, err error)
 | 
			
		||||
 | 
			
		||||
	// AcceptHandshake accepts the client handshake request and sends
 | 
			
		||||
	// handshake response back to client.
 | 
			
		||||
	AcceptHandshake(buf *bufio.Writer) (err error)
 | 
			
		||||
 | 
			
		||||
	// NewServerConn creates a new WebSocket connection.
 | 
			
		||||
	NewServerConn(buf *bufio.ReadWriter, rwc io.ReadWriteCloser, request *http.Request) (conn *Conn)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// frameReader is an interface to read a WebSocket frame.
 | 
			
		||||
type frameReader interface {
 | 
			
		||||
	// Reader is to read payload of the frame.
 | 
			
		||||
	io.Reader
 | 
			
		||||
 | 
			
		||||
	// PayloadType returns payload type.
 | 
			
		||||
	PayloadType() byte
 | 
			
		||||
 | 
			
		||||
	// HeaderReader returns a reader to read header of the frame.
 | 
			
		||||
	HeaderReader() io.Reader
 | 
			
		||||
 | 
			
		||||
	// TrailerReader returns a reader to read trailer of the frame.
 | 
			
		||||
	// If it returns nil, there is no trailer in the frame.
 | 
			
		||||
	TrailerReader() io.Reader
 | 
			
		||||
 | 
			
		||||
	// Len returns total length of the frame, including header and trailer.
 | 
			
		||||
	Len() int
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// frameReaderFactory is an interface to creates new frame reader.
 | 
			
		||||
type frameReaderFactory interface {
 | 
			
		||||
	NewFrameReader() (r frameReader, err error)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// frameWriter is an interface to write a WebSocket frame.
 | 
			
		||||
type frameWriter interface {
 | 
			
		||||
	// Writer is to write payload of the frame.
 | 
			
		||||
	io.WriteCloser
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// frameWriterFactory is an interface to create new frame writer.
 | 
			
		||||
type frameWriterFactory interface {
 | 
			
		||||
	NewFrameWriter(payloadType byte) (w frameWriter, err error)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type frameHandler interface {
 | 
			
		||||
	HandleFrame(frame frameReader) (r frameReader, err error)
 | 
			
		||||
	WriteClose(status int) (err error)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Conn represents a WebSocket connection.
 | 
			
		||||
type Conn struct {
 | 
			
		||||
	config  *Config
 | 
			
		||||
	request *http.Request
 | 
			
		||||
 | 
			
		||||
	buf *bufio.ReadWriter
 | 
			
		||||
	rwc io.ReadWriteCloser
 | 
			
		||||
 | 
			
		||||
	rio sync.Mutex
 | 
			
		||||
	frameReaderFactory
 | 
			
		||||
	frameReader
 | 
			
		||||
 | 
			
		||||
	wio sync.Mutex
 | 
			
		||||
	frameWriterFactory
 | 
			
		||||
 | 
			
		||||
	frameHandler
 | 
			
		||||
	PayloadType        byte
 | 
			
		||||
	defaultCloseStatus int
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Read implements the io.Reader interface:
 | 
			
		||||
// it reads data of a frame from the WebSocket connection.
 | 
			
		||||
// if msg is not large enough for the frame data, it fills the msg and next Read
 | 
			
		||||
// will read the rest of the frame data.
 | 
			
		||||
// it reads Text frame or Binary frame.
 | 
			
		||||
func (ws *Conn) Read(msg []byte) (n int, err error) {
 | 
			
		||||
	ws.rio.Lock()
 | 
			
		||||
	defer ws.rio.Unlock()
 | 
			
		||||
again:
 | 
			
		||||
	if ws.frameReader == nil {
 | 
			
		||||
		frame, err := ws.frameReaderFactory.NewFrameReader()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return 0, err
 | 
			
		||||
		}
 | 
			
		||||
		ws.frameReader, err = ws.frameHandler.HandleFrame(frame)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return 0, err
 | 
			
		||||
		}
 | 
			
		||||
		if ws.frameReader == nil {
 | 
			
		||||
			goto again
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	n, err = ws.frameReader.Read(msg)
 | 
			
		||||
	if err == io.EOF {
 | 
			
		||||
		if trailer := ws.frameReader.TrailerReader(); trailer != nil {
 | 
			
		||||
			io.Copy(ioutil.Discard, trailer)
 | 
			
		||||
		}
 | 
			
		||||
		ws.frameReader = nil
 | 
			
		||||
		goto again
 | 
			
		||||
	}
 | 
			
		||||
	return n, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Write implements the io.Writer interface:
 | 
			
		||||
// it writes data as a frame to the WebSocket connection.
 | 
			
		||||
func (ws *Conn) Write(msg []byte) (n int, err error) {
 | 
			
		||||
	ws.wio.Lock()
 | 
			
		||||
	defer ws.wio.Unlock()
 | 
			
		||||
	w, err := ws.frameWriterFactory.NewFrameWriter(ws.PayloadType)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, err
 | 
			
		||||
	}
 | 
			
		||||
	n, err = w.Write(msg)
 | 
			
		||||
	w.Close()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return n, err
 | 
			
		||||
	}
 | 
			
		||||
	return n, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Close implements the io.Closer interface.
 | 
			
		||||
func (ws *Conn) Close() error {
 | 
			
		||||
	err := ws.frameHandler.WriteClose(ws.defaultCloseStatus)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	return ws.rwc.Close()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (ws *Conn) IsClientConn() bool { return ws.request == nil }
 | 
			
		||||
func (ws *Conn) IsServerConn() bool { return ws.request != nil }
 | 
			
		||||
 | 
			
		||||
// LocalAddr returns the WebSocket Origin for the connection for client, or
 | 
			
		||||
// the WebSocket location for server.
 | 
			
		||||
func (ws *Conn) LocalAddr() net.Addr {
 | 
			
		||||
	if ws.IsClientConn() {
 | 
			
		||||
		return &Addr{ws.config.Origin}
 | 
			
		||||
	}
 | 
			
		||||
	return &Addr{ws.config.Location}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RemoteAddr returns the WebSocket location for the connection for client, or
 | 
			
		||||
// the Websocket Origin for server.
 | 
			
		||||
func (ws *Conn) RemoteAddr() net.Addr {
 | 
			
		||||
	if ws.IsClientConn() {
 | 
			
		||||
		return &Addr{ws.config.Location}
 | 
			
		||||
	}
 | 
			
		||||
	return &Addr{ws.config.Origin}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var errSetDeadline = errors.New("websocket: cannot set deadline: not using a net.Conn")
 | 
			
		||||
 | 
			
		||||
// SetDeadline sets the connection's network read & write deadlines.
 | 
			
		||||
func (ws *Conn) SetDeadline(t time.Time) error {
 | 
			
		||||
	if conn, ok := ws.rwc.(net.Conn); ok {
 | 
			
		||||
		return conn.SetDeadline(t)
 | 
			
		||||
	}
 | 
			
		||||
	return errSetDeadline
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SetReadDeadline sets the connection's network read deadline.
 | 
			
		||||
func (ws *Conn) SetReadDeadline(t time.Time) error {
 | 
			
		||||
	if conn, ok := ws.rwc.(net.Conn); ok {
 | 
			
		||||
		return conn.SetReadDeadline(t)
 | 
			
		||||
	}
 | 
			
		||||
	return errSetDeadline
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SetWriteDeadline sets the connection's network write deadline.
 | 
			
		||||
func (ws *Conn) SetWriteDeadline(t time.Time) error {
 | 
			
		||||
	if conn, ok := ws.rwc.(net.Conn); ok {
 | 
			
		||||
		return conn.SetWriteDeadline(t)
 | 
			
		||||
	}
 | 
			
		||||
	return errSetDeadline
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Config returns the WebSocket config.
 | 
			
		||||
func (ws *Conn) Config() *Config { return ws.config }
 | 
			
		||||
 | 
			
		||||
// Request returns the http request upgraded to the WebSocket.
 | 
			
		||||
// It is nil for client side.
 | 
			
		||||
func (ws *Conn) Request() *http.Request { return ws.request }
 | 
			
		||||
 | 
			
		||||
// Codec represents a symmetric pair of functions that implement a codec.
 | 
			
		||||
type Codec struct {
 | 
			
		||||
	Marshal   func(v interface{}) (data []byte, payloadType byte, err error)
 | 
			
		||||
	Unmarshal func(data []byte, payloadType byte, v interface{}) (err error)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Send sends v marshaled by cd.Marshal as single frame to ws.
 | 
			
		||||
func (cd Codec) Send(ws *Conn, v interface{}) (err error) {
 | 
			
		||||
	data, payloadType, err := cd.Marshal(v)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	ws.wio.Lock()
 | 
			
		||||
	defer ws.wio.Unlock()
 | 
			
		||||
	w, err := ws.frameWriterFactory.NewFrameWriter(payloadType)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	_, err = w.Write(data)
 | 
			
		||||
	w.Close()
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Receive receives single frame from ws, unmarshaled by cd.Unmarshal and stores in v.
 | 
			
		||||
func (cd Codec) Receive(ws *Conn, v interface{}) (err error) {
 | 
			
		||||
	ws.rio.Lock()
 | 
			
		||||
	defer ws.rio.Unlock()
 | 
			
		||||
	if ws.frameReader != nil {
 | 
			
		||||
		_, err = io.Copy(ioutil.Discard, ws.frameReader)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		ws.frameReader = nil
 | 
			
		||||
	}
 | 
			
		||||
again:
 | 
			
		||||
	frame, err := ws.frameReaderFactory.NewFrameReader()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	frame, err = ws.frameHandler.HandleFrame(frame)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if frame == nil {
 | 
			
		||||
		goto again
 | 
			
		||||
	}
 | 
			
		||||
	payloadType := frame.PayloadType()
 | 
			
		||||
	data, err := ioutil.ReadAll(frame)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	return cd.Unmarshal(data, payloadType, v)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func marshal(v interface{}) (msg []byte, payloadType byte, err error) {
 | 
			
		||||
	switch data := v.(type) {
 | 
			
		||||
	case string:
 | 
			
		||||
		return []byte(data), TextFrame, nil
 | 
			
		||||
	case []byte:
 | 
			
		||||
		return data, BinaryFrame, nil
 | 
			
		||||
	}
 | 
			
		||||
	return nil, UnknownFrame, ErrNotSupported
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func unmarshal(msg []byte, payloadType byte, v interface{}) (err error) {
 | 
			
		||||
	switch data := v.(type) {
 | 
			
		||||
	case *string:
 | 
			
		||||
		*data = string(msg)
 | 
			
		||||
		return nil
 | 
			
		||||
	case *[]byte:
 | 
			
		||||
		*data = msg
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	return ErrNotSupported
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
Message is a codec to send/receive text/binary data in a frame on WebSocket connection.
 | 
			
		||||
To send/receive text frame, use string type.
 | 
			
		||||
To send/receive binary frame, use []byte type.
 | 
			
		||||
 | 
			
		||||
Trivial usage:
 | 
			
		||||
 | 
			
		||||
	import "websocket"
 | 
			
		||||
 | 
			
		||||
	// receive text frame
 | 
			
		||||
	var message string
 | 
			
		||||
	websocket.Message.Receive(ws, &message)
 | 
			
		||||
 | 
			
		||||
	// send text frame
 | 
			
		||||
	message = "hello"
 | 
			
		||||
	websocket.Message.Send(ws, message)
 | 
			
		||||
 | 
			
		||||
	// receive binary frame
 | 
			
		||||
	var data []byte
 | 
			
		||||
	websocket.Message.Receive(ws, &data)
 | 
			
		||||
 | 
			
		||||
	// send binary frame
 | 
			
		||||
	data = []byte{0, 1, 2}
 | 
			
		||||
	websocket.Message.Send(ws, data)
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
var Message = Codec{marshal, unmarshal}
 | 
			
		||||
 | 
			
		||||
func jsonMarshal(v interface{}) (msg []byte, payloadType byte, err error) {
 | 
			
		||||
	msg, err = json.Marshal(v)
 | 
			
		||||
	return msg, TextFrame, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func jsonUnmarshal(msg []byte, payloadType byte, v interface{}) (err error) {
 | 
			
		||||
	return json.Unmarshal(msg, v)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
JSON is a codec to send/receive JSON data in a frame from a WebSocket connection.
 | 
			
		||||
 | 
			
		||||
Trivial usage:
 | 
			
		||||
 | 
			
		||||
	import "websocket"
 | 
			
		||||
 | 
			
		||||
	type T struct {
 | 
			
		||||
		Msg string
 | 
			
		||||
		Count int
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// receive JSON type T
 | 
			
		||||
	var data T
 | 
			
		||||
	websocket.JSON.Receive(ws, &data)
 | 
			
		||||
 | 
			
		||||
	// send JSON type T
 | 
			
		||||
	websocket.JSON.Send(ws, data)
 | 
			
		||||
*/
 | 
			
		||||
var JSON = Codec{jsonMarshal, jsonUnmarshal}
 | 
			
		||||
							
								
								
									
										341
									
								
								Godeps/_workspace/src/code.google.com/p/go.net/websocket/websocket_test.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										341
									
								
								Godeps/_workspace/src/code.google.com/p/go.net/websocket/websocket_test.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,341 +0,0 @@
 | 
			
		||||
// Copyright 2009 The Go 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
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"log"
 | 
			
		||||
	"net"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"net/http/httptest"
 | 
			
		||||
	"net/url"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"sync"
 | 
			
		||||
	"testing"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var serverAddr string
 | 
			
		||||
var once sync.Once
 | 
			
		||||
 | 
			
		||||
func echoServer(ws *Conn) { io.Copy(ws, ws) }
 | 
			
		||||
 | 
			
		||||
type Count struct {
 | 
			
		||||
	S string
 | 
			
		||||
	N int
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func countServer(ws *Conn) {
 | 
			
		||||
	for {
 | 
			
		||||
		var count Count
 | 
			
		||||
		err := JSON.Receive(ws, &count)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		count.N++
 | 
			
		||||
		count.S = strings.Repeat(count.S, count.N)
 | 
			
		||||
		err = JSON.Send(ws, count)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func subProtocolHandshake(config *Config, req *http.Request) error {
 | 
			
		||||
	for _, proto := range config.Protocol {
 | 
			
		||||
		if proto == "chat" {
 | 
			
		||||
			config.Protocol = []string{proto}
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return ErrBadWebSocketProtocol
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func subProtoServer(ws *Conn) {
 | 
			
		||||
	for _, proto := range ws.Config().Protocol {
 | 
			
		||||
		io.WriteString(ws, proto)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func startServer() {
 | 
			
		||||
	http.Handle("/echo", Handler(echoServer))
 | 
			
		||||
	http.Handle("/count", Handler(countServer))
 | 
			
		||||
	subproto := Server{
 | 
			
		||||
		Handshake: subProtocolHandshake,
 | 
			
		||||
		Handler:   Handler(subProtoServer),
 | 
			
		||||
	}
 | 
			
		||||
	http.Handle("/subproto", subproto)
 | 
			
		||||
	server := httptest.NewServer(nil)
 | 
			
		||||
	serverAddr = server.Listener.Addr().String()
 | 
			
		||||
	log.Print("Test WebSocket server listening on ", serverAddr)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newConfig(t *testing.T, path string) *Config {
 | 
			
		||||
	config, _ := NewConfig(fmt.Sprintf("ws://%s%s", serverAddr, path), "http://localhost")
 | 
			
		||||
	return config
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestEcho(t *testing.T) {
 | 
			
		||||
	once.Do(startServer)
 | 
			
		||||
 | 
			
		||||
	// websocket.Dial()
 | 
			
		||||
	client, err := net.Dial("tcp", serverAddr)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal("dialing", err)
 | 
			
		||||
	}
 | 
			
		||||
	conn, err := NewClient(newConfig(t, "/echo"), client)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Errorf("WebSocket handshake error: %v", err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	msg := []byte("hello, world\n")
 | 
			
		||||
	if _, err := conn.Write(msg); err != nil {
 | 
			
		||||
		t.Errorf("Write: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	var actual_msg = make([]byte, 512)
 | 
			
		||||
	n, err := conn.Read(actual_msg)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Errorf("Read: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	actual_msg = actual_msg[0:n]
 | 
			
		||||
	if !bytes.Equal(msg, actual_msg) {
 | 
			
		||||
		t.Errorf("Echo: expected %q got %q", msg, actual_msg)
 | 
			
		||||
	}
 | 
			
		||||
	conn.Close()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestAddr(t *testing.T) {
 | 
			
		||||
	once.Do(startServer)
 | 
			
		||||
 | 
			
		||||
	// websocket.Dial()
 | 
			
		||||
	client, err := net.Dial("tcp", serverAddr)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal("dialing", err)
 | 
			
		||||
	}
 | 
			
		||||
	conn, err := NewClient(newConfig(t, "/echo"), client)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Errorf("WebSocket handshake error: %v", err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ra := conn.RemoteAddr().String()
 | 
			
		||||
	if !strings.HasPrefix(ra, "ws://") || !strings.HasSuffix(ra, "/echo") {
 | 
			
		||||
		t.Errorf("Bad remote addr: %v", ra)
 | 
			
		||||
	}
 | 
			
		||||
	la := conn.LocalAddr().String()
 | 
			
		||||
	if !strings.HasPrefix(la, "http://") {
 | 
			
		||||
		t.Errorf("Bad local addr: %v", la)
 | 
			
		||||
	}
 | 
			
		||||
	conn.Close()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestCount(t *testing.T) {
 | 
			
		||||
	once.Do(startServer)
 | 
			
		||||
 | 
			
		||||
	// websocket.Dial()
 | 
			
		||||
	client, err := net.Dial("tcp", serverAddr)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal("dialing", err)
 | 
			
		||||
	}
 | 
			
		||||
	conn, err := NewClient(newConfig(t, "/count"), client)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Errorf("WebSocket handshake error: %v", err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var count Count
 | 
			
		||||
	count.S = "hello"
 | 
			
		||||
	if err := JSON.Send(conn, count); err != nil {
 | 
			
		||||
		t.Errorf("Write: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	if err := JSON.Receive(conn, &count); err != nil {
 | 
			
		||||
		t.Errorf("Read: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	if count.N != 1 {
 | 
			
		||||
		t.Errorf("count: expected %d got %d", 1, count.N)
 | 
			
		||||
	}
 | 
			
		||||
	if count.S != "hello" {
 | 
			
		||||
		t.Errorf("count: expected %q got %q", "hello", count.S)
 | 
			
		||||
	}
 | 
			
		||||
	if err := JSON.Send(conn, count); err != nil {
 | 
			
		||||
		t.Errorf("Write: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	if err := JSON.Receive(conn, &count); err != nil {
 | 
			
		||||
		t.Errorf("Read: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	if count.N != 2 {
 | 
			
		||||
		t.Errorf("count: expected %d got %d", 2, count.N)
 | 
			
		||||
	}
 | 
			
		||||
	if count.S != "hellohello" {
 | 
			
		||||
		t.Errorf("count: expected %q got %q", "hellohello", count.S)
 | 
			
		||||
	}
 | 
			
		||||
	conn.Close()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestWithQuery(t *testing.T) {
 | 
			
		||||
	once.Do(startServer)
 | 
			
		||||
 | 
			
		||||
	client, err := net.Dial("tcp", serverAddr)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal("dialing", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	config := newConfig(t, "/echo")
 | 
			
		||||
	config.Location, err = url.ParseRequestURI(fmt.Sprintf("ws://%s/echo?q=v", serverAddr))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal("location url", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ws, err := NewClient(config, client)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Errorf("WebSocket handshake: %v", err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	ws.Close()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func testWithProtocol(t *testing.T, subproto []string) (string, error) {
 | 
			
		||||
	once.Do(startServer)
 | 
			
		||||
 | 
			
		||||
	client, err := net.Dial("tcp", serverAddr)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal("dialing", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	config := newConfig(t, "/subproto")
 | 
			
		||||
	config.Protocol = subproto
 | 
			
		||||
 | 
			
		||||
	ws, err := NewClient(config, client)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
	msg := make([]byte, 16)
 | 
			
		||||
	n, err := ws.Read(msg)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
	ws.Close()
 | 
			
		||||
	return string(msg[:n]), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestWithProtocol(t *testing.T) {
 | 
			
		||||
	proto, err := testWithProtocol(t, []string{"chat"})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Errorf("SubProto: unexpected error: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	if proto != "chat" {
 | 
			
		||||
		t.Errorf("SubProto: expected %q, got %q", "chat", proto)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestWithTwoProtocol(t *testing.T) {
 | 
			
		||||
	proto, err := testWithProtocol(t, []string{"test", "chat"})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Errorf("SubProto: unexpected error: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	if proto != "chat" {
 | 
			
		||||
		t.Errorf("SubProto: expected %q, got %q", "chat", proto)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestWithBadProtocol(t *testing.T) {
 | 
			
		||||
	_, err := testWithProtocol(t, []string{"test"})
 | 
			
		||||
	if err != ErrBadStatus {
 | 
			
		||||
		t.Errorf("SubProto: expected %v, got %v", ErrBadStatus, err)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestHTTP(t *testing.T) {
 | 
			
		||||
	once.Do(startServer)
 | 
			
		||||
 | 
			
		||||
	// If the client did not send a handshake that matches the protocol
 | 
			
		||||
	// specification, the server MUST return an HTTP response with an
 | 
			
		||||
	// appropriate error code (such as 400 Bad Request)
 | 
			
		||||
	resp, err := http.Get(fmt.Sprintf("http://%s/echo", serverAddr))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Errorf("Get: error %#v", err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if resp == nil {
 | 
			
		||||
		t.Error("Get: resp is null")
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if resp.StatusCode != http.StatusBadRequest {
 | 
			
		||||
		t.Errorf("Get: expected %q got %q", http.StatusBadRequest, resp.StatusCode)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestTrailingSpaces(t *testing.T) {
 | 
			
		||||
	// http://code.google.com/p/go/issues/detail?id=955
 | 
			
		||||
	// The last runs of this create keys with trailing spaces that should not be
 | 
			
		||||
	// generated by the client.
 | 
			
		||||
	once.Do(startServer)
 | 
			
		||||
	config := newConfig(t, "/echo")
 | 
			
		||||
	for i := 0; i < 30; i++ {
 | 
			
		||||
		// body
 | 
			
		||||
		ws, err := DialConfig(config)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			t.Errorf("Dial #%d failed: %v", i, err)
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
		ws.Close()
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestDialConfigBadVersion(t *testing.T) {
 | 
			
		||||
	once.Do(startServer)
 | 
			
		||||
	config := newConfig(t, "/echo")
 | 
			
		||||
	config.Version = 1234
 | 
			
		||||
 | 
			
		||||
	_, err := DialConfig(config)
 | 
			
		||||
 | 
			
		||||
	if dialerr, ok := err.(*DialError); ok {
 | 
			
		||||
		if dialerr.Err != ErrBadProtocolVersion {
 | 
			
		||||
			t.Errorf("dial expected err %q but got %q", ErrBadProtocolVersion, dialerr.Err)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestSmallBuffer(t *testing.T) {
 | 
			
		||||
	// http://code.google.com/p/go/issues/detail?id=1145
 | 
			
		||||
	// Read should be able to handle reading a fragment of a frame.
 | 
			
		||||
	once.Do(startServer)
 | 
			
		||||
 | 
			
		||||
	// websocket.Dial()
 | 
			
		||||
	client, err := net.Dial("tcp", serverAddr)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal("dialing", err)
 | 
			
		||||
	}
 | 
			
		||||
	conn, err := NewClient(newConfig(t, "/echo"), client)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Errorf("WebSocket handshake error: %v", err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	msg := []byte("hello, world\n")
 | 
			
		||||
	if _, err := conn.Write(msg); err != nil {
 | 
			
		||||
		t.Errorf("Write: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	var small_msg = make([]byte, 8)
 | 
			
		||||
	n, err := conn.Read(small_msg)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Errorf("Read: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	if !bytes.Equal(msg[:len(small_msg)], small_msg) {
 | 
			
		||||
		t.Errorf("Echo: expected %q got %q", msg[:len(small_msg)], small_msg)
 | 
			
		||||
	}
 | 
			
		||||
	var second_msg = make([]byte, len(msg))
 | 
			
		||||
	n, err = conn.Read(second_msg)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Errorf("Read: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	second_msg = second_msg[0:n]
 | 
			
		||||
	if !bytes.Equal(msg[len(small_msg):], second_msg) {
 | 
			
		||||
		t.Errorf("Echo: expected %q got %q", msg[len(small_msg):], second_msg)
 | 
			
		||||
	}
 | 
			
		||||
	conn.Close()
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user