package wsimport ()// Errors used by frame reader.var (ErrHeaderLengthMSB = fmt.Errorf("header error: the most significant bit must be 0")ErrHeaderLengthUnexpected = fmt.Errorf("header error: unexpected payload length bits"))// ReadHeader reads a frame header from r.func ( io.Reader) ( Header, error) {// Make slice of bytes with capacity 12 that could hold any header. // // The maximum header size is 14, but due to the 2 hop reads, // after first hop that reads first 2 constant bytes, we could reuse 2 bytes. // So 14 - 2 = 12. := make([]byte, 2, MaxHeaderSize-2)// Prepare to hold first 2 bytes to choose size of next read. _, = io.ReadFull(, )if != nil {return , } .Fin = [0]&bit0 != 0 .Rsv = ([0] & 0x70) >> 4 .OpCode = OpCode([0] & 0x0f)varintif [1]&bit0 != 0 { .Masked = true += 4 } := [1] & 0x7fswitch {case < 126: .Length = int64()case == 126: += 2case == 127: += 8default: = ErrHeaderLengthUnexpectedreturn , }if == 0 {return , }// Increase len of bts to extra bytes need to read. // Overwrite first 2 bytes that was read before. = [:] _, = io.ReadFull(, )if != nil {return , }switch {case == 126: .Length = int64(binary.BigEndian.Uint16([:2])) = [2:]case == 127:if [0]&0x80 != 0 { = ErrHeaderLengthMSBreturn , } .Length = int64(binary.BigEndian.Uint64([:8])) = [8:] }if .Masked {copy(.Mask[:], ) }return , nil}// ReadFrame reads a frame from r.// It is not designed for high optimized use case cause it makes allocation// for frame.Header.Length size inside to read frame payload into.//// Note that ReadFrame does not unmask payload.func ( io.Reader) ( Frame, error) { .Header, = ReadHeader()if != nil {return , }if .Header.Length > 0 {// int(f.Header.Length) is safe here cause we have // checked it for overflow above in ReadHeader. .Payload = make([]byte, int(.Header.Length)) _, = io.ReadFull(, .Payload) }return , }// MustReadFrame is like ReadFrame but panics if frame can not be read.func ( io.Reader) Frame { , := ReadFrame()if != nil {panic() }return}// ParseCloseFrameData parses close frame status code and closure reason if any provided.// If there is no status code in the payload// the empty status code is returned (code.Empty()) with empty string as a reason.func ( []byte) ( StatusCode, string) {iflen() < 2 {// We returning empty StatusCode here, preventing the situation // when endpoint really sent code 1005 and we should return ProtocolError on that. // // In other words, we ignoring this rule [RFC6455:7.1.5]: // If this Close control frame contains no status code, _The WebSocket // Connection Close Code_ is considered to be 1005.return , } = StatusCode(binary.BigEndian.Uint16()) = string([2:])return , }// ParseCloseFrameDataUnsafe is like ParseCloseFrameData except the thing// that it does not copies payload bytes into reason, but prepares unsafe cast.func ( []byte) ( StatusCode, string) {iflen() < 2 {return , } = StatusCode(binary.BigEndian.Uint16()) = btsToString([2:])return , }
The pages are generated with Goldsv0.8.2. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.