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

     1  package wire
     2  
     3  import (
     4  	"errors"
     5  	"io"
     6  
     7  	"github.com/metacubex/quic-go/internal/protocol"
     8  	"github.com/metacubex/quic-go/quicvarint"
     9  )
    10  
    11  // A StreamFrame of QUIC
    12  type StreamFrame struct {
    13  	StreamID       protocol.StreamID
    14  	Offset         protocol.ByteCount
    15  	Data           []byte
    16  	Fin            bool
    17  	DataLenPresent bool
    18  
    19  	fromPool bool
    20  }
    21  
    22  func parseStreamFrame(b []byte, typ uint64, _ protocol.Version) (*StreamFrame, int, error) {
    23  	startLen := len(b)
    24  	hasOffset := typ&0b100 > 0
    25  	fin := typ&0b1 > 0
    26  	hasDataLen := typ&0b10 > 0
    27  
    28  	streamID, l, err := quicvarint.Parse(b)
    29  	if err != nil {
    30  		return nil, 0, replaceUnexpectedEOF(err)
    31  	}
    32  	b = b[l:]
    33  	var offset uint64
    34  	if hasOffset {
    35  		offset, l, err = quicvarint.Parse(b)
    36  		if err != nil {
    37  			return nil, 0, replaceUnexpectedEOF(err)
    38  		}
    39  		b = b[l:]
    40  	}
    41  
    42  	var dataLen uint64
    43  	if hasDataLen {
    44  		var err error
    45  		var l int
    46  		dataLen, l, err = quicvarint.Parse(b)
    47  		if err != nil {
    48  			return nil, 0, replaceUnexpectedEOF(err)
    49  		}
    50  		b = b[l:]
    51  		if dataLen > uint64(len(b)) {
    52  			return nil, 0, io.EOF
    53  		}
    54  	} else {
    55  		// The rest of the packet is data
    56  		dataLen = uint64(len(b))
    57  	}
    58  
    59  	var frame *StreamFrame
    60  	if dataLen < protocol.MinStreamFrameBufferSize {
    61  		frame = &StreamFrame{Data: make([]byte, dataLen)}
    62  	} else {
    63  		frame = GetStreamFrame()
    64  		// The STREAM frame can't be larger than the StreamFrame we obtained from the buffer,
    65  		// since those StreamFrames have a buffer length of the maximum packet size.
    66  		if dataLen > uint64(cap(frame.Data)) {
    67  			return nil, 0, io.EOF
    68  		}
    69  		frame.Data = frame.Data[:dataLen]
    70  	}
    71  
    72  	frame.StreamID = protocol.StreamID(streamID)
    73  	frame.Offset = protocol.ByteCount(offset)
    74  	frame.Fin = fin
    75  	frame.DataLenPresent = hasDataLen
    76  
    77  	if dataLen != 0 {
    78  		copy(frame.Data, b)
    79  	}
    80  	if frame.Offset+frame.DataLen() > protocol.MaxByteCount {
    81  		return nil, 0, errors.New("stream data overflows maximum offset")
    82  	}
    83  	return frame, startLen - len(b) + int(dataLen), nil
    84  }
    85  
    86  func (f *StreamFrame) Append(b []byte, _ protocol.Version) ([]byte, error) {
    87  	if len(f.Data) == 0 && !f.Fin {
    88  		return nil, errors.New("StreamFrame: attempting to write empty frame without FIN")
    89  	}
    90  
    91  	typ := byte(0x8)
    92  	if f.Fin {
    93  		typ ^= 0b1
    94  	}
    95  	hasOffset := f.Offset != 0
    96  	if f.DataLenPresent {
    97  		typ ^= 0b10
    98  	}
    99  	if hasOffset {
   100  		typ ^= 0b100
   101  	}
   102  	b = append(b, typ)
   103  	b = quicvarint.Append(b, uint64(f.StreamID))
   104  	if hasOffset {
   105  		b = quicvarint.Append(b, uint64(f.Offset))
   106  	}
   107  	if f.DataLenPresent {
   108  		b = quicvarint.Append(b, uint64(f.DataLen()))
   109  	}
   110  	b = append(b, f.Data...)
   111  	return b, nil
   112  }
   113  
   114  // Length returns the total length of the STREAM frame
   115  func (f *StreamFrame) Length(protocol.Version) protocol.ByteCount {
   116  	length := 1 + quicvarint.Len(uint64(f.StreamID))
   117  	if f.Offset != 0 {
   118  		length += quicvarint.Len(uint64(f.Offset))
   119  	}
   120  	if f.DataLenPresent {
   121  		length += quicvarint.Len(uint64(f.DataLen()))
   122  	}
   123  	return protocol.ByteCount(length) + f.DataLen()
   124  }
   125  
   126  // DataLen gives the length of data in bytes
   127  func (f *StreamFrame) DataLen() protocol.ByteCount {
   128  	return protocol.ByteCount(len(f.Data))
   129  }
   130  
   131  // MaxDataLen returns the maximum data length
   132  // If 0 is returned, writing will fail (a STREAM frame must contain at least 1 byte of data).
   133  func (f *StreamFrame) MaxDataLen(maxSize protocol.ByteCount, _ protocol.Version) protocol.ByteCount {
   134  	headerLen := 1 + protocol.ByteCount(quicvarint.Len(uint64(f.StreamID)))
   135  	if f.Offset != 0 {
   136  		headerLen += protocol.ByteCount(quicvarint.Len(uint64(f.Offset)))
   137  	}
   138  	if f.DataLenPresent {
   139  		// Pretend that the data size will be 1 byte.
   140  		// If it turns out that varint encoding the length will consume 2 bytes, we need to adjust the data length afterward
   141  		headerLen++
   142  	}
   143  	if headerLen > maxSize {
   144  		return 0
   145  	}
   146  	maxDataLen := maxSize - headerLen
   147  	if f.DataLenPresent && quicvarint.Len(uint64(maxDataLen)) != 1 {
   148  		maxDataLen--
   149  	}
   150  	return maxDataLen
   151  }
   152  
   153  // MaybeSplitOffFrame splits a frame such that it is not bigger than n bytes.
   154  // It returns if the frame was actually split.
   155  // The frame might not be split if:
   156  // * the size is large enough to fit the whole frame
   157  // * the size is too small to fit even a 1-byte frame. In that case, the frame returned is nil.
   158  func (f *StreamFrame) MaybeSplitOffFrame(maxSize protocol.ByteCount, version protocol.Version) (*StreamFrame, bool /* was splitting required */) {
   159  	if maxSize >= f.Length(version) {
   160  		return nil, false
   161  	}
   162  
   163  	n := f.MaxDataLen(maxSize, version)
   164  	if n == 0 {
   165  		return nil, true
   166  	}
   167  
   168  	new := GetStreamFrame()
   169  	new.StreamID = f.StreamID
   170  	new.Offset = f.Offset
   171  	new.Fin = false
   172  	new.DataLenPresent = f.DataLenPresent
   173  
   174  	// swap the data slices
   175  	new.Data, f.Data = f.Data, new.Data
   176  	new.fromPool, f.fromPool = f.fromPool, new.fromPool
   177  
   178  	f.Data = f.Data[:protocol.ByteCount(len(new.Data))-n]
   179  	copy(f.Data, new.Data[n:])
   180  	new.Data = new.Data[:n]
   181  	f.Offset += n
   182  
   183  	return new, true
   184  }
   185  
   186  func (f *StreamFrame) PutBack() {
   187  	putStreamFrame(f)
   188  }