Godeps: delete golang.org/x/net/websocket
It is no longer imported by any package in our tree.
This commit is contained in:
		
							parent
							
								
									bdba044a80
								
							
						
					
					
						commit
						f9c6bc63df
					
				
							
								
								
									
										4
									
								
								Godeps/Godeps.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										4
									
								
								Godeps/Godeps.json
									
									
									
										generated
									
									
									
								
							| @ -97,10 +97,6 @@ | ||||
| 			"ImportPath": "golang.org/x/crypto/scrypt", | ||||
| 			"Rev": "4ed45ec682102c643324fae5dff8dab085b6c300" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"ImportPath": "golang.org/x/net/websocket", | ||||
| 			"Rev": "59b0df9b1f7abda5aab0495ee54f408daf182ce7" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"ImportPath": "gopkg.in/check.v1", | ||||
| 			"Rev": "64131543e7896d5bcc6bd5a76287eb75ea96c673" | ||||
|  | ||||
							
								
								
									
										112
									
								
								Godeps/_workspace/src/golang.org/x/net/websocket/client.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										112
									
								
								Godeps/_workspace/src/golang.org/x/net/websocket/client.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -1,112 +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) | ||||
| } | ||||
| 
 | ||||
| var portMap = map[string]string{ | ||||
| 	"ws":  "80", | ||||
| 	"wss": "443", | ||||
| } | ||||
| 
 | ||||
| func parseAuthority(location *url.URL) string { | ||||
| 	if _, ok := portMap[location.Scheme]; ok { | ||||
| 		if _, _, err := net.SplitHostPort(location.Host); err != nil { | ||||
| 			return net.JoinHostPort(location.Host, portMap[location.Scheme]) | ||||
| 		} | ||||
| 	} | ||||
| 	return location.Host | ||||
| } | ||||
| 
 | ||||
| // 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", parseAuthority(config.Location)) | ||||
| 
 | ||||
| 	case "wss": | ||||
| 		client, err = tls.Dial("tcp", parseAuthority(config.Location), 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/golang.org/x/net/websocket/exampledial_test.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										31
									
								
								Godeps/_workspace/src/golang.org/x/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" | ||||
| 
 | ||||
| 	"golang.org/x/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/golang.org/x/net/websocket/examplehandler_test.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										26
									
								
								Godeps/_workspace/src/golang.org/x/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" | ||||
| 
 | ||||
| 	"golang.org/x/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/golang.org/x/net/websocket/hybi.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										564
									
								
								Godeps/_workspace/src/golang.org/x/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/golang.org/x/net/websocket/hybi_test.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										590
									
								
								Godeps/_workspace/src/golang.org/x/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/golang.org/x/net/websocket/server.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										114
									
								
								Godeps/_workspace/src/golang.org/x/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/golang.org/x/net/websocket/websocket.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										411
									
								
								Godeps/_workspace/src/golang.org/x/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} | ||||
							
								
								
									
										414
									
								
								Godeps/_workspace/src/golang.org/x/net/websocket/websocket_test.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										414
									
								
								Godeps/_workspace/src/golang.org/x/net/websocket/websocket_test.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -1,414 +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() | ||||
| } | ||||
| 
 | ||||
| var parseAuthorityTests = []struct { | ||||
| 	in  *url.URL | ||||
| 	out string | ||||
| }{ | ||||
| 	{ | ||||
| 		&url.URL{ | ||||
| 			Scheme: "ws", | ||||
| 			Host:   "www.google.com", | ||||
| 		}, | ||||
| 		"www.google.com:80", | ||||
| 	}, | ||||
| 	{ | ||||
| 		&url.URL{ | ||||
| 			Scheme: "wss", | ||||
| 			Host:   "www.google.com", | ||||
| 		}, | ||||
| 		"www.google.com:443", | ||||
| 	}, | ||||
| 	{ | ||||
| 		&url.URL{ | ||||
| 			Scheme: "ws", | ||||
| 			Host:   "www.google.com:80", | ||||
| 		}, | ||||
| 		"www.google.com:80", | ||||
| 	}, | ||||
| 	{ | ||||
| 		&url.URL{ | ||||
| 			Scheme: "wss", | ||||
| 			Host:   "www.google.com:443", | ||||
| 		}, | ||||
| 		"www.google.com:443", | ||||
| 	}, | ||||
| 	// some invalid ones for parseAuthority. parseAuthority doesn't
 | ||||
| 	// concern itself with the scheme unless it actually knows about it
 | ||||
| 	{ | ||||
| 		&url.URL{ | ||||
| 			Scheme: "http", | ||||
| 			Host:   "www.google.com", | ||||
| 		}, | ||||
| 		"www.google.com", | ||||
| 	}, | ||||
| 	{ | ||||
| 		&url.URL{ | ||||
| 			Scheme: "http", | ||||
| 			Host:   "www.google.com:80", | ||||
| 		}, | ||||
| 		"www.google.com:80", | ||||
| 	}, | ||||
| 	{ | ||||
| 		&url.URL{ | ||||
| 			Scheme: "asdf", | ||||
| 			Host:   "127.0.0.1", | ||||
| 		}, | ||||
| 		"127.0.0.1", | ||||
| 	}, | ||||
| 	{ | ||||
| 		&url.URL{ | ||||
| 			Scheme: "asdf", | ||||
| 			Host:   "www.google.com", | ||||
| 		}, | ||||
| 		"www.google.com", | ||||
| 	}, | ||||
| } | ||||
| 
 | ||||
| func TestParseAuthority(t *testing.T) { | ||||
| 	for _, tt := range parseAuthorityTests { | ||||
| 		out := parseAuthority(tt.in) | ||||
| 		if out != tt.out { | ||||
| 			t.Errorf("got %v; want %v", out, tt.out) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user