forked from quic-go/quic-go
This function was needed when we supported both Q039 (using big endian encoding) and ealier versions (using little endian encoding).
198 lines
4.6 KiB
Go
198 lines
4.6 KiB
Go
package wire
|
|
|
|
import (
|
|
"bytes"
|
|
"errors"
|
|
"io"
|
|
|
|
"github.com/lucas-clemente/quic-go/internal/protocol"
|
|
"github.com/lucas-clemente/quic-go/internal/utils"
|
|
"github.com/lucas-clemente/quic-go/qerr"
|
|
)
|
|
|
|
var (
|
|
errInvalidStreamIDLen = errors.New("StreamFrame: Invalid StreamID length")
|
|
errInvalidOffsetLen = errors.New("StreamFrame: Invalid offset length")
|
|
)
|
|
|
|
// parseLegacyStreamFrame reads a stream frame. The type byte must not have been read yet.
|
|
func parseLegacyStreamFrame(r *bytes.Reader, _ protocol.VersionNumber) (*StreamFrame, error) {
|
|
frame := &StreamFrame{}
|
|
|
|
typeByte, err := r.ReadByte()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
frame.FinBit = typeByte&0x40 > 0
|
|
frame.DataLenPresent = typeByte&0x20 > 0
|
|
offsetLen := typeByte & 0x1c >> 2
|
|
if offsetLen != 0 {
|
|
offsetLen++
|
|
}
|
|
streamIDLen := typeByte&0x3 + 1
|
|
|
|
sid, err := utils.BigEndian.ReadUintN(r, streamIDLen)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
frame.StreamID = protocol.StreamID(sid)
|
|
|
|
offset, err := utils.BigEndian.ReadUintN(r, offsetLen)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
frame.Offset = protocol.ByteCount(offset)
|
|
|
|
var dataLen uint16
|
|
if frame.DataLenPresent {
|
|
dataLen, err = utils.BigEndian.ReadUint16(r)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
// shortcut to prevent the unneccessary allocation of dataLen bytes
|
|
// if the dataLen is larger than the remaining length of the packet
|
|
// reading the packet contents would result in EOF when attempting to READ
|
|
if int(dataLen) > r.Len() {
|
|
return nil, io.EOF
|
|
}
|
|
|
|
if !frame.DataLenPresent {
|
|
// The rest of the packet is data
|
|
dataLen = uint16(r.Len())
|
|
}
|
|
if dataLen != 0 {
|
|
frame.Data = make([]byte, dataLen)
|
|
if _, err := io.ReadFull(r, frame.Data); err != nil {
|
|
// this should never happen, since we already checked the dataLen earlier
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
// MaxByteCount is the highest value that can be encoded with the IETF QUIC variable integer encoding (2^62-1).
|
|
// Note that this value is smaller than the maximum value that could be encoded in the gQUIC STREAM frame (2^64-1).
|
|
if frame.Offset+frame.DataLen() > protocol.MaxByteCount {
|
|
return nil, qerr.Error(qerr.InvalidStreamData, "data overflows maximum offset")
|
|
}
|
|
if !frame.FinBit && frame.DataLen() == 0 {
|
|
return nil, qerr.EmptyStreamFrameNoFin
|
|
}
|
|
return frame, nil
|
|
}
|
|
|
|
// writeLegacy writes a stream frame.
|
|
func (f *StreamFrame) writeLegacy(b *bytes.Buffer, _ protocol.VersionNumber) error {
|
|
if len(f.Data) == 0 && !f.FinBit {
|
|
return errors.New("StreamFrame: attempting to write empty frame without FIN")
|
|
}
|
|
|
|
typeByte := uint8(0x80) // sets the leftmost bit to 1
|
|
if f.FinBit {
|
|
typeByte ^= 0x40
|
|
}
|
|
if f.DataLenPresent {
|
|
typeByte ^= 0x20
|
|
}
|
|
|
|
offsetLength := f.getOffsetLength()
|
|
if offsetLength > 0 {
|
|
typeByte ^= (uint8(offsetLength) - 1) << 2
|
|
}
|
|
|
|
streamIDLen := f.calculateStreamIDLength()
|
|
typeByte ^= streamIDLen - 1
|
|
|
|
b.WriteByte(typeByte)
|
|
|
|
switch streamIDLen {
|
|
case 1:
|
|
b.WriteByte(uint8(f.StreamID))
|
|
case 2:
|
|
utils.BigEndian.WriteUint16(b, uint16(f.StreamID))
|
|
case 3:
|
|
utils.BigEndian.WriteUint24(b, uint32(f.StreamID))
|
|
case 4:
|
|
utils.BigEndian.WriteUint32(b, uint32(f.StreamID))
|
|
default:
|
|
return errInvalidStreamIDLen
|
|
}
|
|
|
|
switch offsetLength {
|
|
case 0:
|
|
case 2:
|
|
utils.BigEndian.WriteUint16(b, uint16(f.Offset))
|
|
case 3:
|
|
utils.BigEndian.WriteUint24(b, uint32(f.Offset))
|
|
case 4:
|
|
utils.BigEndian.WriteUint32(b, uint32(f.Offset))
|
|
case 5:
|
|
utils.BigEndian.WriteUint40(b, uint64(f.Offset))
|
|
case 6:
|
|
utils.BigEndian.WriteUint48(b, uint64(f.Offset))
|
|
case 7:
|
|
utils.BigEndian.WriteUint56(b, uint64(f.Offset))
|
|
case 8:
|
|
utils.BigEndian.WriteUint64(b, uint64(f.Offset))
|
|
default:
|
|
return errInvalidOffsetLen
|
|
}
|
|
|
|
if f.DataLenPresent {
|
|
utils.BigEndian.WriteUint16(b, uint16(len(f.Data)))
|
|
}
|
|
|
|
b.Write(f.Data)
|
|
return nil
|
|
}
|
|
|
|
func (f *StreamFrame) calculateStreamIDLength() uint8 {
|
|
if f.StreamID < (1 << 8) {
|
|
return 1
|
|
} else if f.StreamID < (1 << 16) {
|
|
return 2
|
|
} else if f.StreamID < (1 << 24) {
|
|
return 3
|
|
}
|
|
return 4
|
|
}
|
|
|
|
func (f *StreamFrame) getOffsetLength() protocol.ByteCount {
|
|
if f.Offset == 0 {
|
|
return 0
|
|
}
|
|
if f.Offset < (1 << 16) {
|
|
return 2
|
|
}
|
|
if f.Offset < (1 << 24) {
|
|
return 3
|
|
}
|
|
if f.Offset < (1 << 32) {
|
|
return 4
|
|
}
|
|
if f.Offset < (1 << 40) {
|
|
return 5
|
|
}
|
|
if f.Offset < (1 << 48) {
|
|
return 6
|
|
}
|
|
if f.Offset < (1 << 56) {
|
|
return 7
|
|
}
|
|
return 8
|
|
}
|
|
|
|
func (f *StreamFrame) minLengthLegacy(_ protocol.VersionNumber) (protocol.ByteCount, error) {
|
|
length := protocol.ByteCount(1) + protocol.ByteCount(f.calculateStreamIDLength()) + f.getOffsetLength()
|
|
if f.DataLenPresent {
|
|
length += 2
|
|
}
|
|
return length, nil
|
|
}
|
|
|
|
// DataLen gives the length of data in bytes
|
|
func (f *StreamFrame) DataLen() protocol.ByteCount {
|
|
return protocol.ByteCount(len(f.Data))
|
|
}
|