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