package wire
import (
"errors"
"io"
"github.com/quic-go/quic-go/internal/protocol"
"github.com/quic-go/quic-go/quicvarint"
)
type StreamFrame struct {
StreamID protocol .StreamID
Offset protocol .ByteCount
Data []byte
Fin bool
DataLenPresent bool
fromPool bool
}
func parseStreamFrame(b []byte , typ uint64 , _ protocol .Version ) (*StreamFrame , int , error ) {
startLen := len (b )
hasOffset := typ &0b100 > 0
fin := typ &0b1 > 0
hasDataLen := typ &0b10 > 0
streamID , l , err := quicvarint .Parse (b )
if err != nil {
return nil , 0 , replaceUnexpectedEOF (err )
}
b = b [l :]
var offset uint64
if hasOffset {
offset , l , err = quicvarint .Parse (b )
if err != nil {
return nil , 0 , replaceUnexpectedEOF (err )
}
b = b [l :]
}
var dataLen uint64
if hasDataLen {
var err error
var l int
dataLen , l , err = quicvarint .Parse (b )
if err != nil {
return nil , 0 , replaceUnexpectedEOF (err )
}
b = b [l :]
if dataLen > uint64 (len (b )) {
return nil , 0 , io .EOF
}
} else {
dataLen = uint64 (len (b ))
}
var frame *StreamFrame
if dataLen < protocol .MinStreamFrameBufferSize {
frame = &StreamFrame {}
if dataLen > 0 {
frame .Data = make ([]byte , dataLen )
}
} else {
frame = GetStreamFrame ()
if dataLen > uint64 (cap (frame .Data )) {
return nil , 0 , io .EOF
}
frame .Data = frame .Data [:dataLen ]
}
frame .StreamID = protocol .StreamID (streamID )
frame .Offset = protocol .ByteCount (offset )
frame .Fin = fin
frame .DataLenPresent = hasDataLen
if dataLen > 0 {
copy (frame .Data , b )
}
if frame .Offset +frame .DataLen () > protocol .MaxByteCount {
return nil , 0 , errors .New ("stream data overflows maximum offset" )
}
return frame , startLen - len (b ) + int (dataLen ), nil
}
func (f *StreamFrame ) Append (b []byte , _ protocol .Version ) ([]byte , error ) {
if len (f .Data ) == 0 && !f .Fin {
return nil , errors .New ("StreamFrame: attempting to write empty frame without FIN" )
}
typ := byte (0x8 )
if f .Fin {
typ ^= 0b1
}
hasOffset := f .Offset != 0
if f .DataLenPresent {
typ ^= 0b10
}
if hasOffset {
typ ^= 0b100
}
b = append (b , typ )
b = quicvarint .Append (b , uint64 (f .StreamID ))
if hasOffset {
b = quicvarint .Append (b , uint64 (f .Offset ))
}
if f .DataLenPresent {
b = quicvarint .Append (b , uint64 (f .DataLen ()))
}
b = append (b , f .Data ...)
return b , nil
}
func (f *StreamFrame ) Length (protocol .Version ) protocol .ByteCount {
length := 1 + quicvarint .Len (uint64 (f .StreamID ))
if f .Offset != 0 {
length += quicvarint .Len (uint64 (f .Offset ))
}
if f .DataLenPresent {
length += quicvarint .Len (uint64 (f .DataLen ()))
}
return protocol .ByteCount (length ) + f .DataLen ()
}
func (f *StreamFrame ) DataLen () protocol .ByteCount {
return protocol .ByteCount (len (f .Data ))
}
func (f *StreamFrame ) MaxDataLen (maxSize protocol .ByteCount , _ protocol .Version ) protocol .ByteCount {
headerLen := 1 + protocol .ByteCount (quicvarint .Len (uint64 (f .StreamID )))
if f .Offset != 0 {
headerLen += protocol .ByteCount (quicvarint .Len (uint64 (f .Offset )))
}
if f .DataLenPresent {
headerLen ++
}
if headerLen > maxSize {
return 0
}
maxDataLen := maxSize - headerLen
if f .DataLenPresent && quicvarint .Len (uint64 (maxDataLen )) != 1 {
maxDataLen --
}
return maxDataLen
}
func (f *StreamFrame ) MaybeSplitOffFrame (maxSize protocol .ByteCount , version protocol .Version ) (*StreamFrame , bool ) {
if maxSize >= f .Length (version ) {
return nil , false
}
n := f .MaxDataLen (maxSize , version )
if n == 0 {
return nil , true
}
new := GetStreamFrame ()
new .StreamID = f .StreamID
new .Offset = f .Offset
new .Fin = false
new .DataLenPresent = f .DataLenPresent
new .Data , f .Data = f .Data , new .Data
new .fromPool , f .fromPool = f .fromPool , new .fromPool
f .Data = f .Data [:protocol .ByteCount (len (new .Data ))-n ]
copy (f .Data , new .Data [n :])
new .Data = new .Data [:n ]
f .Offset += n
return new , true
}
func (f *StreamFrame ) PutBack () {
putStreamFrame (f )
}
The pages are generated with Golds v0.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 .