105 lines
1.8 KiB
Go
105 lines
1.8 KiB
Go
package ws
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"io"
|
|
)
|
|
|
|
// Header size length bounds in bytes.
|
|
const (
|
|
MaxHeaderSize = 14
|
|
MinHeaderSize = 2
|
|
)
|
|
|
|
const (
|
|
bit0 = 0x80
|
|
bit1 = 0x40
|
|
bit2 = 0x20
|
|
bit3 = 0x10
|
|
bit4 = 0x08
|
|
bit5 = 0x04
|
|
bit6 = 0x02
|
|
bit7 = 0x01
|
|
|
|
len7 = int64(125)
|
|
len16 = int64(^(uint16(0)))
|
|
len64 = int64(^(uint64(0)) >> 1)
|
|
)
|
|
|
|
// HeaderSize returns number of bytes that are needed to encode given header.
|
|
// It returns -1 if header is malformed.
|
|
func HeaderSize(h Header) (n int) {
|
|
switch {
|
|
case h.Length < 126:
|
|
n = 2
|
|
case h.Length <= len16:
|
|
n = 4
|
|
case h.Length <= len64:
|
|
n = 10
|
|
default:
|
|
return -1
|
|
}
|
|
if h.Masked {
|
|
n += len(h.Mask)
|
|
}
|
|
return n
|
|
}
|
|
|
|
// WriteHeader writes header binary representation into w.
|
|
func WriteHeader(w io.Writer, h Header) error {
|
|
// Make slice of bytes with capacity 14 that could hold any header.
|
|
bts := make([]byte, MaxHeaderSize)
|
|
|
|
if h.Fin {
|
|
bts[0] |= bit0
|
|
}
|
|
bts[0] |= h.Rsv << 4
|
|
bts[0] |= byte(h.OpCode)
|
|
|
|
var n int
|
|
switch {
|
|
case h.Length <= len7:
|
|
bts[1] = byte(h.Length)
|
|
n = 2
|
|
|
|
case h.Length <= len16:
|
|
bts[1] = 126
|
|
binary.BigEndian.PutUint16(bts[2:4], uint16(h.Length))
|
|
n = 4
|
|
|
|
case h.Length <= len64:
|
|
bts[1] = 127
|
|
binary.BigEndian.PutUint64(bts[2:10], uint64(h.Length))
|
|
n = 10
|
|
|
|
default:
|
|
return ErrHeaderLengthUnexpected
|
|
}
|
|
|
|
if h.Masked {
|
|
bts[1] |= bit0
|
|
n += copy(bts[n:], h.Mask[:])
|
|
}
|
|
|
|
_, err := w.Write(bts[:n])
|
|
|
|
return err
|
|
}
|
|
|
|
// WriteFrame writes frame binary representation into w.
|
|
func WriteFrame(w io.Writer, f Frame) error {
|
|
err := WriteHeader(w, f.Header)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
_, err = w.Write(f.Payload)
|
|
return err
|
|
}
|
|
|
|
// MustWriteFrame is like WriteFrame but panics if frame can not be read.
|
|
func MustWriteFrame(w io.Writer, f Frame) {
|
|
if err := WriteFrame(w, f); err != nil {
|
|
panic(err)
|
|
}
|
|
}
|