github.com/metacubex/quic-go@v0.44.1-0.20240520163451-20b689a59136/internal/wire/crypto_frame.go (about)

     1  package wire
     2  
     3  import (
     4  	"io"
     5  
     6  	"github.com/metacubex/quic-go/internal/protocol"
     7  	"github.com/metacubex/quic-go/quicvarint"
     8  )
     9  
    10  // A CryptoFrame is a CRYPTO frame
    11  type CryptoFrame struct {
    12  	Offset protocol.ByteCount
    13  	Data   []byte
    14  }
    15  
    16  func parseCryptoFrame(b []byte, _ protocol.Version) (*CryptoFrame, int, error) {
    17  	startLen := len(b)
    18  	frame := &CryptoFrame{}
    19  	offset, l, err := quicvarint.Parse(b)
    20  	if err != nil {
    21  		return nil, 0, replaceUnexpectedEOF(err)
    22  	}
    23  	b = b[l:]
    24  	frame.Offset = protocol.ByteCount(offset)
    25  	dataLen, l, err := quicvarint.Parse(b)
    26  	if err != nil {
    27  		return nil, 0, replaceUnexpectedEOF(err)
    28  	}
    29  	b = b[l:]
    30  	if dataLen > uint64(len(b)) {
    31  		return nil, 0, io.EOF
    32  	}
    33  	if dataLen != 0 {
    34  		frame.Data = make([]byte, dataLen)
    35  		copy(frame.Data, b)
    36  	}
    37  	return frame, startLen - len(b) + int(dataLen), nil
    38  }
    39  
    40  func (f *CryptoFrame) Append(b []byte, _ protocol.Version) ([]byte, error) {
    41  	b = append(b, cryptoFrameType)
    42  	b = quicvarint.Append(b, uint64(f.Offset))
    43  	b = quicvarint.Append(b, uint64(len(f.Data)))
    44  	b = append(b, f.Data...)
    45  	return b, nil
    46  }
    47  
    48  // Length of a written frame
    49  func (f *CryptoFrame) Length(_ protocol.Version) protocol.ByteCount {
    50  	return protocol.ByteCount(1 + quicvarint.Len(uint64(f.Offset)) + quicvarint.Len(uint64(len(f.Data))) + len(f.Data))
    51  }
    52  
    53  // MaxDataLen returns the maximum data length
    54  func (f *CryptoFrame) MaxDataLen(maxSize protocol.ByteCount) protocol.ByteCount {
    55  	// pretend that the data size will be 1 bytes
    56  	// if it turns out that varint encoding the length will consume 2 bytes, we need to adjust the data length afterwards
    57  	headerLen := protocol.ByteCount(1 + quicvarint.Len(uint64(f.Offset)) + 1)
    58  	if headerLen > maxSize {
    59  		return 0
    60  	}
    61  	maxDataLen := maxSize - headerLen
    62  	if quicvarint.Len(uint64(maxDataLen)) != 1 {
    63  		maxDataLen--
    64  	}
    65  	return maxDataLen
    66  }
    67  
    68  // MaybeSplitOffFrame splits a frame such that it is not bigger than n bytes.
    69  // It returns if the frame was actually split.
    70  // The frame might not be split if:
    71  // * the size is large enough to fit the whole frame
    72  // * the size is too small to fit even a 1-byte frame. In that case, the frame returned is nil.
    73  func (f *CryptoFrame) MaybeSplitOffFrame(maxSize protocol.ByteCount, version protocol.Version) (*CryptoFrame, bool /* was splitting required */) {
    74  	if f.Length(version) <= maxSize {
    75  		return nil, false
    76  	}
    77  
    78  	n := f.MaxDataLen(maxSize)
    79  	if n == 0 {
    80  		return nil, true
    81  	}
    82  
    83  	newLen := protocol.ByteCount(len(f.Data)) - n
    84  
    85  	new := &CryptoFrame{}
    86  	new.Offset = f.Offset
    87  	new.Data = make([]byte, newLen)
    88  
    89  	// swap the data slices
    90  	new.Data, f.Data = f.Data, new.Data
    91  
    92  	copy(f.Data, new.Data[n:])
    93  	new.Data = new.Data[:n]
    94  	f.Offset += n
    95  
    96  	return new, true
    97  }