summaryrefslogtreecommitdiff
path: root/src/pkg/websocket
diff options
context:
space:
mode:
authorOndřej Surý <ondrej@sury.org>2011-09-13 13:11:55 +0200
committerOndřej Surý <ondrej@sury.org>2011-09-13 13:11:55 +0200
commit80f18fc933cf3f3e829c5455a1023d69f7b86e52 (patch)
tree4b825dc642cb6eb9a060e54bf8d69288fbee4904 /src/pkg/websocket
parent28592ee1ea1f5cdffcf85472f9de0285d928cf12 (diff)
downloadgolang-80f18fc933cf3f3e829c5455a1023d69f7b86e52.tar.gz
Imported Upstream version 60
Diffstat (limited to 'src/pkg/websocket')
-rw-r--r--src/pkg/websocket/Makefile9
-rw-r--r--src/pkg/websocket/client.go323
-rw-r--r--src/pkg/websocket/server.go220
-rw-r--r--src/pkg/websocket/websocket.go192
-rw-r--r--src/pkg/websocket/websocket_test.go270
5 files changed, 0 insertions, 1014 deletions
diff --git a/src/pkg/websocket/Makefile b/src/pkg/websocket/Makefile
deleted file mode 100644
index 6d3c9cbd1..000000000
--- a/src/pkg/websocket/Makefile
+++ /dev/null
@@ -1,9 +0,0 @@
-include ../../Make.inc
-
-TARG=websocket
-GOFILES=\
- client.go\
- server.go\
- websocket.go\
-
-include ../../Make.pkg
diff --git a/src/pkg/websocket/client.go b/src/pkg/websocket/client.go
deleted file mode 100644
index f066a1832..000000000
--- a/src/pkg/websocket/client.go
+++ /dev/null
@@ -1,323 +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"
- "bytes"
- "container/vector"
- "crypto/tls"
- "fmt"
- "http"
- "io"
- "net"
- "os"
- "rand"
- "strings"
-)
-
-type ProtocolError struct {
- ErrorString string
-}
-
-func (err *ProtocolError) String() string { return string(err.ErrorString) }
-
-var (
- 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"}
- ErrChallengeResponse = &ProtocolError{"mismatch challenge/response"}
- secKeyRandomChars [0x30 - 0x21 + 0x7F - 0x3A]byte
-)
-
-type DialError struct {
- URL string
- Protocol string
- Origin string
- Error os.Error
-}
-
-func (e *DialError) String() string {
- return "websocket.Dial " + e.URL + ": " + e.Error.String()
-}
-
-func init() {
- i := 0
- for ch := byte(0x21); ch < 0x30; ch++ {
- secKeyRandomChars[i] = ch
- i++
- }
- for ch := byte(0x3a); ch < 0x7F; ch++ {
- secKeyRandomChars[i] = ch
- i++
- }
-}
-
-type handshaker func(resourceName, host, origin, location, protocol string, br *bufio.Reader, bw *bufio.Writer) os.Error
-
-// newClient creates a new Web Socket client connection.
-func newClient(resourceName, host, origin, location, protocol string, rwc io.ReadWriteCloser, handshake handshaker) (ws *Conn, err os.Error) {
- br := bufio.NewReader(rwc)
- bw := bufio.NewWriter(rwc)
- err = handshake(resourceName, host, origin, location, protocol, br, bw)
- if err != nil {
- return
- }
- buf := bufio.NewReadWriter(br, bw)
- ws = newConn(origin, location, protocol, buf, rwc)
- return
-}
-
-/*
-Dial opens a new client connection to a Web Socket.
-
-A trivial example client:
-
- package main
-
- import (
- "websocket"
- "strings"
- )
-
- func main() {
- ws, err := websocket.Dial("ws://localhost/ws", "", "http://localhost/");
- if err != nil {
- panic("Dial: " + err.String())
- }
- if _, err := ws.Write([]byte("hello, world!\n")); err != nil {
- panic("Write: " + err.String())
- }
- var msg = make([]byte, 512);
- if n, err := ws.Read(msg); err != nil {
- panic("Read: " + err.String())
- }
- // use msg[0:n]
- }
-*/
-func Dial(url, protocol, origin string) (ws *Conn, err os.Error) {
- var client net.Conn
-
- parsedUrl, err := http.ParseURL(url)
- if err != nil {
- goto Error
- }
-
- switch parsedUrl.Scheme {
- case "ws":
- client, err = net.Dial("tcp", parsedUrl.Host)
-
- case "wss":
- client, err = tls.Dial("tcp", parsedUrl.Host, nil)
-
- default:
- err = ErrBadScheme
- }
- if err != nil {
- goto Error
- }
-
- ws, err = newClient(parsedUrl.RawPath, parsedUrl.Host, origin, url, protocol, client, handshake)
- if err != nil {
- goto Error
- }
- return
-
-Error:
- return nil, &DialError{url, protocol, origin, err}
-}
-
-/*
-Generates handshake key as described in 4.1 Opening handshake step 16 to 22.
-cf. http://www.whatwg.org/specs/web-socket-protocol/
-*/
-func generateKeyNumber() (key string, number uint32) {
- // 16. Let /spaces_n/ be a random integer from 1 to 12 inclusive.
- spaces := rand.Intn(12) + 1
-
- // 17. Let /max_n/ be the largest integer not greater than
- // 4,294,967,295 divided by /spaces_n/
- max := int(4294967295 / uint32(spaces))
-
- // 18. Let /number_n/ be a random integer from 0 to /max_n/ inclusive.
- number = uint32(rand.Intn(max + 1))
-
- // 19. Let /product_n/ be the result of multiplying /number_n/ and
- // /spaces_n/ together.
- product := number * uint32(spaces)
-
- // 20. Let /key_n/ be a string consisting of /product_n/, expressed
- // in base ten using the numerals in the range U+0030 DIGIT ZERO (0)
- // to U+0039 DIGIT NINE (9).
- key = fmt.Sprintf("%d", product)
-
- // 21. Insert between one and twelve random characters from the ranges
- // U+0021 to U+002F and U+003A to U+007E into /key_n/ at random
- // positions.
- n := rand.Intn(12) + 1
- for i := 0; i < n; i++ {
- pos := rand.Intn(len(key)) + 1
- ch := secKeyRandomChars[rand.Intn(len(secKeyRandomChars))]
- key = key[0:pos] + string(ch) + key[pos:]
- }
-
- // 22. Insert /spaces_n/ U+0020 SPACE characters into /key_n/ at random
- // positions other than the start or end of the string.
- for i := 0; i < spaces; i++ {
- pos := rand.Intn(len(key)-1) + 1
- key = key[0:pos] + " " + key[pos:]
- }
-
- return
-}
-
-/*
-Generates handshake key_3 as described in 4.1 Opening handshake step 26.
-cf. http://www.whatwg.org/specs/web-socket-protocol/
-*/
-func generateKey3() (key []byte) {
- // 26. Let /key3/ be a string consisting of eight random bytes (or
- // equivalently, a random 64 bit integer encoded in big-endian order).
- key = make([]byte, 8)
- for i := 0; i < 8; i++ {
- key[i] = byte(rand.Intn(256))
- }
- return
-}
-
-/*
-Web Socket protocol handshake based on
-http://www.whatwg.org/specs/web-socket-protocol/
-(draft of http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol)
-*/
-func handshake(resourceName, host, origin, location, protocol string, br *bufio.Reader, bw *bufio.Writer) (err os.Error) {
- // 4.1. Opening handshake.
- // Step 5. send a request line.
- bw.WriteString("GET " + resourceName + " HTTP/1.1\r\n")
-
- // Step 6-14. push request headers in fields.
- var fields vector.StringVector
- fields.Push("Upgrade: WebSocket\r\n")
- fields.Push("Connection: Upgrade\r\n")
- fields.Push("Host: " + host + "\r\n")
- fields.Push("Origin: " + origin + "\r\n")
- if protocol != "" {
- fields.Push("Sec-WebSocket-Protocol: " + protocol + "\r\n")
- }
- // TODO(ukai): Step 15. send cookie if any.
-
- // Step 16-23. generate keys and push Sec-WebSocket-Key<n> in fields.
- key1, number1 := generateKeyNumber()
- key2, number2 := generateKeyNumber()
- fields.Push("Sec-WebSocket-Key1: " + key1 + "\r\n")
- fields.Push("Sec-WebSocket-Key2: " + key2 + "\r\n")
-
- // Step 24. shuffle fields and send them out.
- for i := 1; i < len(fields); i++ {
- j := rand.Intn(i)
- fields[i], fields[j] = fields[j], fields[i]
- }
- for i := 0; i < len(fields); i++ {
- bw.WriteString(fields[i])
- }
- // Step 25. send CRLF.
- bw.WriteString("\r\n")
-
- // Step 26. generate 8 bytes random key.
- key3 := generateKey3()
- // Step 27. send it out.
- bw.Write(key3)
- if err = bw.Flush(); err != nil {
- return
- }
-
- // Step 28-29, 32-40. read response from server.
- resp, err := http.ReadResponse(br, &http.Request{Method: "GET"})
- if err != nil {
- return err
- }
- // Step 30. check response code is 101.
- if resp.StatusCode != 101 {
- return ErrBadStatus
- }
-
- // Step 41. check websocket headers.
- if resp.Header.Get("Upgrade") != "WebSocket" ||
- strings.ToLower(resp.Header.Get("Connection")) != "upgrade" {
- return ErrBadUpgrade
- }
-
- if resp.Header.Get("Sec-Websocket-Origin") != origin {
- return ErrBadWebSocketOrigin
- }
-
- if resp.Header.Get("Sec-Websocket-Location") != location {
- return ErrBadWebSocketLocation
- }
-
- if protocol != "" && resp.Header.Get("Sec-Websocket-Protocol") != protocol {
- return ErrBadWebSocketProtocol
- }
-
- // Step 42-43. get expected data from challenge data.
- expected, err := getChallengeResponse(number1, number2, key3)
- if err != nil {
- return err
- }
-
- // Step 44. read 16 bytes from server.
- reply := make([]byte, 16)
- if _, err = io.ReadFull(br, reply); err != nil {
- return err
- }
-
- // Step 45. check the reply equals to expected data.
- if !bytes.Equal(expected, reply) {
- return ErrChallengeResponse
- }
- // WebSocket connection is established.
- return
-}
-
-/*
-Handshake described in (soon obsolete)
-draft-hixie-thewebsocket-protocol-75.
-*/
-func draft75handshake(resourceName, host, origin, location, protocol string, br *bufio.Reader, bw *bufio.Writer) (err os.Error) {
- bw.WriteString("GET " + resourceName + " HTTP/1.1\r\n")
- bw.WriteString("Upgrade: WebSocket\r\n")
- bw.WriteString("Connection: Upgrade\r\n")
- bw.WriteString("Host: " + host + "\r\n")
- bw.WriteString("Origin: " + origin + "\r\n")
- if protocol != "" {
- bw.WriteString("WebSocket-Protocol: " + protocol + "\r\n")
- }
- bw.WriteString("\r\n")
- bw.Flush()
- resp, err := http.ReadResponse(br, &http.Request{Method: "GET"})
- if err != nil {
- return
- }
- if resp.Status != "101 Web Socket Protocol Handshake" {
- return ErrBadStatus
- }
- if resp.Header.Get("Upgrade") != "WebSocket" ||
- resp.Header.Get("Connection") != "Upgrade" {
- return ErrBadUpgrade
- }
- if resp.Header.Get("Websocket-Origin") != origin {
- return ErrBadWebSocketOrigin
- }
- if resp.Header.Get("Websocket-Location") != location {
- return ErrBadWebSocketLocation
- }
- if protocol != "" && resp.Header.Get("Websocket-Protocol") != protocol {
- return ErrBadWebSocketProtocol
- }
- return
-}
diff --git a/src/pkg/websocket/server.go b/src/pkg/websocket/server.go
deleted file mode 100644
index 165cbffee..000000000
--- a/src/pkg/websocket/server.go
+++ /dev/null
@@ -1,220 +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 (
- "http"
- "io"
- "strings"
-)
-
-/*
-Handler is an interface to a WebSocket.
-
-A trivial example server:
-
- package main
-
- import (
- "http"
- "io"
- "websocket"
- )
-
- // Echo the data received on the Web Socket.
- func EchoServer(ws *websocket.Conn) {
- io.Copy(ws, ws);
- }
-
- func main() {
- http.Handle("/echo", websocket.Handler(EchoServer));
- err := http.ListenAndServe(":12345", nil);
- if err != nil {
- panic("ListenAndServe: " + err.String())
- }
- }
-*/
-type Handler func(*Conn)
-
-/*
-Gets key number from Sec-WebSocket-Key<n>: field as described
-in 5.2 Sending the server's opening handshake, 4.
-*/
-func getKeyNumber(s string) (r uint32) {
- // 4. Let /key-number_n/ be the digits (characters in the range
- // U+0030 DIGIT ZERO (0) to U+0039 DIGIT NINE (9)) in /key_1/,
- // interpreted as a base ten integer, ignoring all other characters
- // in /key_n/.
- r = 0
- for i := 0; i < len(s); i++ {
- if s[i] >= '0' && s[i] <= '9' {
- r = r*10 + uint32(s[i]) - '0'
- }
- }
- return
-}
-
-// ServeHTTP implements the http.Handler interface for a Web Socket
-func (f Handler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
- rwc, buf, err := w.(http.Hijacker).Hijack()
- if err != nil {
- panic("Hijack failed: " + err.String())
- 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()
-
- if req.Method != "GET" {
- return
- }
- // HTTP version can be safely ignored.
-
- if strings.ToLower(req.Header.Get("Upgrade")) != "websocket" ||
- strings.ToLower(req.Header.Get("Connection")) != "upgrade" {
- return
- }
-
- // TODO(ukai): check Host
- origin := req.Header.Get("Origin")
- if origin == "" {
- return
- }
-
- key1 := req.Header.Get("Sec-Websocket-Key1")
- if key1 == "" {
- return
- }
- key2 := req.Header.Get("Sec-Websocket-Key2")
- if key2 == "" {
- return
- }
- key3 := make([]byte, 8)
- if _, err := io.ReadFull(buf, key3); err != nil {
- return
- }
-
- var location string
- if req.TLS != nil {
- location = "wss://" + req.Host + req.URL.RawPath
- } else {
- location = "ws://" + req.Host + req.URL.RawPath
- }
-
- // Step 4. get key number in Sec-WebSocket-Key<n> fields.
- keyNumber1 := getKeyNumber(key1)
- keyNumber2 := getKeyNumber(key2)
-
- // Step 5. get number of spaces in Sec-WebSocket-Key<n> fields.
- space1 := uint32(strings.Count(key1, " "))
- space2 := uint32(strings.Count(key2, " "))
- if space1 == 0 || space2 == 0 {
- return
- }
-
- // Step 6. key number must be an integral multiple of spaces.
- if keyNumber1%space1 != 0 || keyNumber2%space2 != 0 {
- return
- }
-
- // Step 7. let part be key number divided by spaces.
- part1 := keyNumber1 / space1
- part2 := keyNumber2 / space2
-
- // Step 8. let challenge be concatenation of part1, part2 and key3.
- // Step 9. get MD5 fingerprint of challenge.
- response, err := getChallengeResponse(part1, part2, key3)
- if err != nil {
- return
- }
-
- // Step 10. send response status line.
- buf.WriteString("HTTP/1.1 101 WebSocket Protocol Handshake\r\n")
- // Step 11. send response headers.
- buf.WriteString("Upgrade: WebSocket\r\n")
- buf.WriteString("Connection: Upgrade\r\n")
- buf.WriteString("Sec-WebSocket-Location: " + location + "\r\n")
- buf.WriteString("Sec-WebSocket-Origin: " + origin + "\r\n")
- protocol := strings.TrimSpace(req.Header.Get("Sec-Websocket-Protocol"))
- if protocol != "" {
- buf.WriteString("Sec-WebSocket-Protocol: " + protocol + "\r\n")
- }
- // Step 12. send CRLF.
- buf.WriteString("\r\n")
- // Step 13. send response data.
- buf.Write(response)
- if err := buf.Flush(); err != nil {
- return
- }
- ws := newConn(origin, location, protocol, buf, rwc)
- ws.Request = req
- f(ws)
-}
-
-
-/*
-Draft75Handler is an interface to a WebSocket based on the
-(soon obsolete) draft-hixie-thewebsocketprotocol-75.
-*/
-type Draft75Handler func(*Conn)
-
-// ServeHTTP implements the http.Handler interface for a Web Socket.
-func (f Draft75Handler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
- if req.Method != "GET" || req.Proto != "HTTP/1.1" {
- w.WriteHeader(http.StatusBadRequest)
- io.WriteString(w, "Unexpected request")
- return
- }
- if req.Header.Get("Upgrade") != "WebSocket" {
- w.WriteHeader(http.StatusBadRequest)
- io.WriteString(w, "missing Upgrade: WebSocket header")
- return
- }
- if req.Header.Get("Connection") != "Upgrade" {
- w.WriteHeader(http.StatusBadRequest)
- io.WriteString(w, "missing Connection: Upgrade header")
- return
- }
- origin := strings.TrimSpace(req.Header.Get("Origin"))
- if origin == "" {
- w.WriteHeader(http.StatusBadRequest)
- io.WriteString(w, "missing Origin header")
- return
- }
-
- rwc, buf, err := w.(http.Hijacker).Hijack()
- if err != nil {
- panic("Hijack failed: " + err.String())
- return
- }
- defer rwc.Close()
-
- var location string
- if req.TLS != nil {
- location = "wss://" + req.Host + req.URL.RawPath
- } else {
- location = "ws://" + req.Host + req.URL.RawPath
- }
-
- // TODO(ukai): verify origin,location,protocol.
-
- buf.WriteString("HTTP/1.1 101 Web Socket Protocol Handshake\r\n")
- buf.WriteString("Upgrade: WebSocket\r\n")
- buf.WriteString("Connection: Upgrade\r\n")
- buf.WriteString("WebSocket-Origin: " + origin + "\r\n")
- buf.WriteString("WebSocket-Location: " + location + "\r\n")
- protocol := strings.TrimSpace(req.Header.Get("Websocket-Protocol"))
- // canonical header key of WebSocket-Protocol.
- if protocol != "" {
- buf.WriteString("WebSocket-Protocol: " + protocol + "\r\n")
- }
- buf.WriteString("\r\n")
- if err := buf.Flush(); err != nil {
- return
- }
- ws := newConn(origin, location, protocol, buf, rwc)
- f(ws)
-}
diff --git a/src/pkg/websocket/websocket.go b/src/pkg/websocket/websocket.go
deleted file mode 100644
index 7447cf852..000000000
--- a/src/pkg/websocket/websocket.go
+++ /dev/null
@@ -1,192 +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 Web Socket protocol.
-// The protocol is defined at http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol
-package websocket
-
-// TODO(ukai):
-// better logging.
-
-import (
- "bufio"
- "crypto/md5"
- "encoding/binary"
- "http"
- "io"
- "net"
- "os"
-)
-
-// WebSocketAddr is an implementation of net.Addr for Web Sockets.
-type WebSocketAddr string
-
-// Network returns the network type for a Web Socket, "websocket".
-func (addr WebSocketAddr) Network() string { return "websocket" }
-
-// String returns the network address for a Web Socket.
-func (addr WebSocketAddr) String() string { return string(addr) }
-
-const (
- stateFrameByte = iota
- stateFrameLength
- stateFrameData
- stateFrameTextData
-)
-
-// Conn is a channel to communicate to a Web Socket.
-// It implements the net.Conn interface.
-type Conn struct {
- // The origin URI for the Web Socket.
- Origin string
- // The location URI for the Web Socket.
- Location string
- // The subprotocol for the Web Socket.
- Protocol string
- // The initial http Request (for the Server side only).
- Request *http.Request
-
- buf *bufio.ReadWriter
- rwc io.ReadWriteCloser
-
- // It holds text data in previous Read() that failed with small buffer.
- data []byte
- reading bool
-}
-
-// newConn creates a new Web Socket.
-func newConn(origin, location, protocol string, buf *bufio.ReadWriter, rwc io.ReadWriteCloser) *Conn {
- if buf == nil {
- br := bufio.NewReader(rwc)
- bw := bufio.NewWriter(rwc)
- buf = bufio.NewReadWriter(br, bw)
- }
- ws := &Conn{Origin: origin, Location: location, Protocol: protocol, buf: buf, rwc: rwc}
- return ws
-}
-
-// Read implements the io.Reader interface for a Conn.
-func (ws *Conn) Read(msg []byte) (n int, err os.Error) {
-Frame:
- for !ws.reading && len(ws.data) == 0 {
- // Beginning of frame, possibly.
- b, err := ws.buf.ReadByte()
- if err != nil {
- return 0, err
- }
- if b&0x80 == 0x80 {
- // Skip length frame.
- length := 0
- for {
- c, err := ws.buf.ReadByte()
- if err != nil {
- return 0, err
- }
- length = length*128 + int(c&0x7f)
- if c&0x80 == 0 {
- break
- }
- }
- for length > 0 {
- _, err := ws.buf.ReadByte()
- if err != nil {
- return 0, err
- }
- }
- continue Frame
- }
- // In text mode
- if b != 0 {
- // Skip this frame
- for {
- c, err := ws.buf.ReadByte()
- if err != nil {
- return 0, err
- }
- if c == '\xff' {
- break
- }
- }
- continue Frame
- }
- ws.reading = true
- }
- if len(ws.data) == 0 {
- ws.data, err = ws.buf.ReadSlice('\xff')
- if err == nil {
- ws.reading = false
- ws.data = ws.data[:len(ws.data)-1] // trim \xff
- }
- }
- n = copy(msg, ws.data)
- ws.data = ws.data[n:]
- return n, err
-}
-
-// Write implements the io.Writer interface for a Conn.
-func (ws *Conn) Write(msg []byte) (n int, err os.Error) {
- ws.buf.WriteByte(0)
- ws.buf.Write(msg)
- ws.buf.WriteByte(0xff)
- err = ws.buf.Flush()
- return len(msg), err
-}
-
-// Close implements the io.Closer interface for a Conn.
-func (ws *Conn) Close() os.Error { return ws.rwc.Close() }
-
-// LocalAddr returns the WebSocket Origin for the connection.
-func (ws *Conn) LocalAddr() net.Addr { return WebSocketAddr(ws.Origin) }
-
-// RemoteAddr returns the WebSocket locations for the connection.
-func (ws *Conn) RemoteAddr() net.Addr { return WebSocketAddr(ws.Location) }
-
-// SetTimeout sets the connection's network timeout in nanoseconds.
-func (ws *Conn) SetTimeout(nsec int64) os.Error {
- if conn, ok := ws.rwc.(net.Conn); ok {
- return conn.SetTimeout(nsec)
- }
- return os.EINVAL
-}
-
-// SetReadTimeout sets the connection's network read timeout in nanoseconds.
-func (ws *Conn) SetReadTimeout(nsec int64) os.Error {
- if conn, ok := ws.rwc.(net.Conn); ok {
- return conn.SetReadTimeout(nsec)
- }
- return os.EINVAL
-}
-
-// SetWriteTimeout sets the connection's network write timeout in nanoseconds.
-func (ws *Conn) SetWriteTimeout(nsec int64) os.Error {
- if conn, ok := ws.rwc.(net.Conn); ok {
- return conn.SetWriteTimeout(nsec)
- }
- return os.EINVAL
-}
-
-// getChallengeResponse computes the expected response from the
-// challenge as described in section 5.1 Opening Handshake steps 42 to
-// 43 of http://www.whatwg.org/specs/web-socket-protocol/
-func getChallengeResponse(number1, number2 uint32, key3 []byte) (expected []byte, err os.Error) {
- // 41. Let /challenge/ be the concatenation of /number_1/, expressed
- // a big-endian 32 bit integer, /number_2/, expressed in a big-
- // endian 32 bit integer, and the eight bytes of /key_3/ in the
- // order they were sent to the wire.
- challenge := make([]byte, 16)
- binary.BigEndian.PutUint32(challenge[0:], number1)
- binary.BigEndian.PutUint32(challenge[4:], number2)
- copy(challenge[8:], key3)
-
- // 42. Let /expected/ be the MD5 fingerprint of /challenge/ as a big-
- // endian 128 bit string.
- h := md5.New()
- if _, err = h.Write(challenge); err != nil {
- return
- }
- expected = h.Sum()
- return
-}
-
-var _ net.Conn = (*Conn)(nil) // compile-time check that *Conn implements net.Conn.
diff --git a/src/pkg/websocket/websocket_test.go b/src/pkg/websocket/websocket_test.go
deleted file mode 100644
index 84788b416..000000000
--- a/src/pkg/websocket/websocket_test.go
+++ /dev/null
@@ -1,270 +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"
- "bytes"
- "fmt"
- "http"
- "http/httptest"
- "io"
- "log"
- "net"
- "sync"
- "testing"
-)
-
-var serverAddr string
-var once sync.Once
-
-func echoServer(ws *Conn) { io.Copy(ws, ws) }
-
-func startServer() {
- http.Handle("/echo", Handler(echoServer))
- http.Handle("/echoDraft75", Draft75Handler(echoServer))
- server := httptest.NewServer(nil)
- serverAddr = server.Listener.Addr().String()
- log.Print("Test WebSocket server listening on ", serverAddr)
-}
-
-// Test the getChallengeResponse function with values from section
-// 5.1 of the specification steps 18, 26, and 43 from
-// http://www.whatwg.org/specs/web-socket-protocol/
-func TestChallenge(t *testing.T) {
- var part1 uint32 = 777007543
- var part2 uint32 = 114997259
- key3 := []byte{0x47, 0x30, 0x22, 0x2D, 0x5A, 0x3F, 0x47, 0x58}
- expected := []byte("0st3Rl&q-2ZU^weu")
-
- response, err := getChallengeResponse(part1, part2, key3)
- if err != nil {
- t.Errorf("getChallengeResponse: returned error %v", err)
- return
- }
- if !bytes.Equal(expected, response) {
- t.Errorf("getChallengeResponse: expected %q got %q", expected, response)
- }
-}
-
-func TestEcho(t *testing.T) {
- once.Do(startServer)
-
- // websocket.Dial()
- client, err := net.Dial("tcp", serverAddr)
- if err != nil {
- t.Fatal("dialing", err)
- }
- ws, err := newClient("/echo", "localhost", "http://localhost",
- "ws://localhost/echo", "", client, handshake)
- if err != nil {
- t.Errorf("WebSocket handshake error: %v", err)
- return
- }
-
- msg := []byte("hello, world\n")
- if _, err := ws.Write(msg); err != nil {
- t.Errorf("Write: %v", err)
- }
- var actual_msg = make([]byte, 512)
- n, err := ws.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)
- }
- ws.Close()
-}
-
-func TestEchoDraft75(t *testing.T) {
- once.Do(startServer)
-
- // websocket.Dial()
- client, err := net.Dial("tcp", serverAddr)
- if err != nil {
- t.Fatal("dialing", err)
- }
- ws, err := newClient("/echoDraft75", "localhost", "http://localhost",
- "ws://localhost/echoDraft75", "", client, draft75handshake)
- if err != nil {
- t.Errorf("WebSocket handshake: %v", err)
- return
- }
-
- msg := []byte("hello, world\n")
- if _, err := ws.Write(msg); err != nil {
- t.Errorf("Write: error %v", err)
- }
- var actual_msg = make([]byte, 512)
- n, err := ws.Read(actual_msg)
- if err != nil {
- t.Errorf("Read: error %v", err)
- }
- actual_msg = actual_msg[0:n]
- if !bytes.Equal(msg, actual_msg) {
- t.Errorf("Echo: expected %q got %q", msg, actual_msg)
- }
- ws.Close()
-}
-
-func TestWithQuery(t *testing.T) {
- once.Do(startServer)
-
- client, err := net.Dial("tcp", serverAddr)
- if err != nil {
- t.Fatal("dialing", err)
- }
-
- ws, err := newClient("/echo?q=v", "localhost", "http://localhost",
- "ws://localhost/echo?q=v", "", client, handshake)
- if err != nil {
- t.Errorf("WebSocket handshake: %v", err)
- return
- }
- ws.Close()
-}
-
-func TestWithProtocol(t *testing.T) {
- once.Do(startServer)
-
- client, err := net.Dial("tcp", serverAddr)
- if err != nil {
- t.Fatal("dialing", err)
- }
-
- ws, err := newClient("/echo", "localhost", "http://localhost",
- "ws://localhost/echo", "test", client, handshake)
- if err != nil {
- t.Errorf("WebSocket handshake: %v", err)
- return
- }
- ws.Close()
-}
-
-func TestHTTP(t *testing.T) {
- once.Do(startServer)
-
- // If the client did not send a handshake that matches the protocol
- // specification, the server should abort the WebSocket connection.
- _, err := http.Get(fmt.Sprintf("http://%s/echo", serverAddr))
- if err == nil {
- t.Error("Get: unexpected success")
- return
- }
- urlerr, ok := err.(*http.URLError)
- if !ok {
- t.Errorf("Get: not URLError %#v", err)
- return
- }
- if urlerr.Error != io.ErrUnexpectedEOF {
- t.Errorf("Get: error %#v", err)
- return
- }
-}
-
-func TestHTTPDraft75(t *testing.T) {
- once.Do(startServer)
-
- r, err := http.Get(fmt.Sprintf("http://%s/echoDraft75", serverAddr))
- if err != nil {
- t.Errorf("Get: error %#v", err)
- return
- }
- if r.StatusCode != http.StatusBadRequest {
- t.Errorf("Get: got status %d", r.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)
- for i := 0; i < 30; i++ {
- // body
- ws, err := Dial(fmt.Sprintf("ws://%s/echo", serverAddr), "", "http://localhost/")
- if err != nil {
- t.Error("Dial failed:", err.String())
- break
- }
- ws.Close()
- }
-}
-
-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)
- }
- ws, err := newClient("/echo", "localhost", "http://localhost",
- "ws://localhost/echo", "", client, handshake)
- if err != nil {
- t.Errorf("WebSocket handshake error: %v", err)
- return
- }
-
- msg := []byte("hello, world\n")
- if _, err := ws.Write(msg); err != nil {
- t.Errorf("Write: %v", err)
- }
- var small_msg = make([]byte, 8)
- n, err := ws.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 = ws.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)
- }
- ws.Close()
-
-}
-
-func testSkipLengthFrame(t *testing.T) {
- b := []byte{'\x80', '\x01', 'x', 0, 'h', 'e', 'l', 'l', 'o', '\xff'}
- buf := bytes.NewBuffer(b)
- br := bufio.NewReader(buf)
- bw := bufio.NewWriter(buf)
- ws := newConn("http://127.0.0.1/", "ws://127.0.0.1/", "", bufio.NewReadWriter(br, bw), nil)
- msg := make([]byte, 5)
- n, err := ws.Read(msg)
- if err != nil {
- t.Errorf("Read: %v", err)
- }
- if !bytes.Equal(b[4:8], msg[0:n]) {
- t.Errorf("Read: expected %q got %q", msg[4:8], msg[0:n])
- }
-}
-
-func testSkipNoUTF8Frame(t *testing.T) {
- b := []byte{'\x01', 'n', '\xff', 0, 'h', 'e', 'l', 'l', 'o', '\xff'}
- buf := bytes.NewBuffer(b)
- br := bufio.NewReader(buf)
- bw := bufio.NewWriter(buf)
- ws := newConn("http://127.0.0.1/", "ws://127.0.0.1/", "", bufio.NewReadWriter(br, bw), nil)
- msg := make([]byte, 5)
- n, err := ws.Read(msg)
- if err != nil {
- t.Errorf("Read: %v", err)
- }
- if !bytes.Equal(b[4:8], msg[0:n]) {
- t.Errorf("Read: expected %q got %q", msg[4:8], msg[0:n])
- }
-}