1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980 |
- package ws
- import (
- "bufio"
- "bytes"
- "crypto/sha1"
- "encoding/base64"
- "fmt"
- "math/rand"
- )
- const (
- // RFC6455: The value of this header field MUST be a nonce consisting of a
- // randomly selected 16-byte value that has been base64-encoded (see
- // Section 4 of [RFC4648]). The nonce MUST be selected randomly for each
- // connection.
- nonceKeySize = 16
- nonceSize = 24 // base64.StdEncoding.EncodedLen(nonceKeySize)
- // RFC6455: The value of this header field is constructed by concatenating
- // /key/, defined above in step 4 in Section 4.2.2, with the string
- // "258EAFA5- E914-47DA-95CA-C5AB0DC85B11", taking the SHA-1 hash of this
- // concatenated value to obtain a 20-byte value and base64- encoding (see
- // Section 4 of [RFC4648]) this 20-byte hash.
- acceptSize = 28 // base64.StdEncoding.EncodedLen(sha1.Size)
- )
- // initNonce fills given slice with random base64-encoded nonce bytes.
- func initNonce(dst []byte) {
- // NOTE: bts does not escape.
- bts := make([]byte, nonceKeySize)
- if _, err := rand.Read(bts); err != nil {
- panic(fmt.Sprintf("rand read error: %s", err))
- }
- base64.StdEncoding.Encode(dst, bts)
- }
- // checkAcceptFromNonce reports whether given accept bytes are valid for given
- // nonce bytes.
- func checkAcceptFromNonce(accept, nonce []byte) bool {
- if len(accept) != acceptSize {
- return false
- }
- // NOTE: expect does not escape.
- expect := make([]byte, acceptSize)
- initAcceptFromNonce(expect, nonce)
- return bytes.Equal(expect, accept)
- }
- // initAcceptFromNonce fills given slice with accept bytes generated from given
- // nonce bytes. Given buffer should be exactly acceptSize bytes.
- func initAcceptFromNonce(accept, nonce []byte) {
- const magic = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
- if len(accept) != acceptSize {
- panic("accept buffer is invalid")
- }
- if len(nonce) != nonceSize {
- panic("nonce is invalid")
- }
- p := make([]byte, nonceSize+len(magic))
- copy(p[:nonceSize], nonce)
- copy(p[nonceSize:], magic)
- sum := sha1.Sum(p)
- base64.StdEncoding.Encode(accept, sum[:])
- return
- }
- func writeAccept(bw *bufio.Writer, nonce []byte) (int, error) {
- accept := make([]byte, acceptSize)
- initAcceptFromNonce(accept, nonce)
- // NOTE: write accept bytes as a string to prevent heap allocation –
- // WriteString() copy given string into its inner buffer, unlike Write()
- // which may write p directly to the underlying io.Writer – which in turn
- // will lead to p escape.
- return bw.WriteString(btsToString(accept))
- }
|