diff options
author | Ondřej Surý <ondrej@sury.org> | 2011-01-17 12:40:45 +0100 |
---|---|---|
committer | Ondřej Surý <ondrej@sury.org> | 2011-01-17 12:40:45 +0100 |
commit | 3e45412327a2654a77944249962b3652e6142299 (patch) | |
tree | bc3bf69452afa055423cbe0c5cfa8ca357df6ccf /src/pkg/websocket/client.go | |
parent | c533680039762cacbc37db8dc7eed074c3e497be (diff) | |
download | golang-3e45412327a2654a77944249962b3652e6142299.tar.gz |
Imported Upstream version 2011.01.12upstream/2011.01.12
Diffstat (limited to 'src/pkg/websocket/client.go')
-rw-r--r-- | src/pkg/websocket/client.go | 113 |
1 files changed, 59 insertions, 54 deletions
diff --git a/src/pkg/websocket/client.go b/src/pkg/websocket/client.go index 2966450a6..091345944 100644 --- a/src/pkg/websocket/client.go +++ b/src/pkg/websocket/client.go @@ -5,11 +5,10 @@ package websocket import ( - "encoding/binary" "bufio" "bytes" "container/vector" - "crypto/md5" + "crypto/tls" "fmt" "http" "io" @@ -24,6 +23,7 @@ type ProtocolError struct { } var ( + ErrBadScheme = os.ErrorString("bad scheme") ErrBadStatus = &ProtocolError{"bad status"} ErrBadUpgrade = &ProtocolError{"missing or bad upgrade"} ErrBadWebSocketOrigin = &ProtocolError{"missing or bad WebSocket-Origin"} @@ -33,6 +33,17 @@ var ( 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++ { @@ -61,8 +72,9 @@ func newClient(resourceName, host, origin, location, protocol string, rwc io.Rea } /* - Dial opens a new client connection to a Web Socket. - A trivial example client is: +Dial opens a new client connection to a Web Socket. + +A trivial example client: package main @@ -87,21 +99,40 @@ func newClient(resourceName, host, origin, location, protocol string, rwc io.Rea } */ func Dial(url, protocol, origin string) (ws *Conn, err os.Error) { + var client net.Conn + parsedUrl, err := http.ParseURL(url) if err != nil { - return + 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 } - client, err := net.Dial("tcp", "", parsedUrl.Host) if err != nil { - return + goto Error } - return newClient(parsedUrl.RawPath, parsedUrl.Host, origin, url, protocol, client, handshake) + + 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/ +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. @@ -123,14 +154,7 @@ func generateKeyNumber() (key string, number uint32) { // to U+0039 DIGIT NINE (9). key = fmt.Sprintf("%d", product) - // 21. Insert /spaces_n/ U+0020 SPACE characters into /key_n/ at random - // posisions. - for i := 0; i < spaces; i++ { - pos := rand.Intn(len(key)-1) + 1 - key = key[0:pos] + " " + key[pos:] - } - - // 22. Insert between one and twelve random characters from the ranges + // 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 @@ -139,13 +163,20 @@ func generateKeyNumber() (key string, number uint32) { 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/ +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 @@ -158,35 +189,9 @@ func generateKey3() (key []byte) { } /* - Gets expected from challenge as described in 4.1 Opening handshake - Step 42 to 43. - cf. http://www.whatwg.org/specs/web-socket-protocol/ -*/ -func getExpectedForChallenge(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) - challengeBuf := bytes.NewBuffer(challenge) - binary.Write(challengeBuf, binary.BigEndian, number1) - binary.Write(challengeBuf, binary.BigEndian, 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 -} - -/* - Web Socket protocol handshake based on - http://www.whatwg.org/specs/web-socket-protocol/ - (draft of http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol) +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. @@ -258,7 +263,7 @@ func handshake(resourceName, host, origin, location, protocol string, br *bufio. } // Step 42-43. get expected data from challange data. - expected, err := getExpectedForChallenge(number1, number2, key3) + expected, err := getChallengeResponse(number1, number2, key3) if err != nil { return err } @@ -278,8 +283,8 @@ func handshake(resourceName, host, origin, location, protocol string, br *bufio. } /* - Handhake described in (soon obsolete) - draft-hixie-thewebsocket-protocol-75. +Handhake 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") |