package websocket
import (
- "encoding/binary"
"bufio"
"bytes"
"container/vector"
- "crypto/md5"
"fmt"
"http"
"io"
return
}
-/*
-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/
}
// 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
}
package websocket
import (
- "bytes"
- "crypto/md5"
- "encoding/binary"
"http"
"io"
"strings"
part2 := keyNumber2 / space2
// Step 8. let challenge to be concatination of part1, part2 and key3.
- challenge := make([]byte, 16)
- challengeBuf := bytes.NewBuffer(challenge)
- err = binary.Write(challengeBuf, binary.BigEndian, part1)
- if err != nil {
- return
- }
- err = binary.Write(challengeBuf, binary.BigEndian, part2)
- if err != nil {
- return
- }
- if n := copy(challenge[8:], key3); n != 8 {
- return
- }
// Step 9. get MD5 fingerprint of challenge.
- h := md5.New()
- if _, err = h.Write(challenge); err != nil {
+ response, err := getChallengeResponse(part1, part2, key3)
+ if err != nil {
return
}
- response := h.Sum()
// Step 10. send response status line.
buf.WriteString("HTTP/1.1 101 WebSocket Protocol Handshake\r\n")
import (
"bufio"
+ "crypto/md5"
+ "encoding/binary"
"io"
"net"
"os"
return os.EINVAL
}
-// SeWritetTimeout sets the connection's network write timeout in nanoseconds.
+// SetWritetTimeout 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.
go http.Serve(l, nil)
}
+// 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)