forked from quic-go/quic-go
implement parsing of stream frames
This commit is contained in:
72
frame.go
Normal file
72
frame.go
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
package quic
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"io/ioutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A StreamFrame of QUIC
|
||||||
|
type StreamFrame struct {
|
||||||
|
FinBit bool
|
||||||
|
DataLengthPresent bool
|
||||||
|
OffsetLength uint8
|
||||||
|
StreamIDLength uint8
|
||||||
|
StreamID uint32
|
||||||
|
Offset uint64
|
||||||
|
DataLength uint16
|
||||||
|
Data []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseStreamFrame reads a stream frame. The type byte must not have been read yet.
|
||||||
|
func ParseStreamFrame(r *bytes.Reader) (*StreamFrame, error) {
|
||||||
|
frame := &StreamFrame{}
|
||||||
|
|
||||||
|
typeByte, err := r.ReadByte()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
frame.FinBit = typeByte&0x40 > 0
|
||||||
|
frame.DataLengthPresent = typeByte&0x20 > 0
|
||||||
|
frame.OffsetLength = typeByte & 0x1C >> 2
|
||||||
|
if frame.OffsetLength != 0 {
|
||||||
|
frame.OffsetLength++
|
||||||
|
}
|
||||||
|
frame.StreamIDLength = typeByte&0x03 + 1
|
||||||
|
|
||||||
|
sid, err := readUint64(r, frame.StreamIDLength)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
frame.StreamID = uint32(sid)
|
||||||
|
|
||||||
|
frame.Offset, err = readUint64(r, frame.OffsetLength)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if frame.DataLengthPresent {
|
||||||
|
var b1, b2 byte
|
||||||
|
if b1, err = r.ReadByte(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if b2, err = r.ReadByte(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
frame.DataLength = uint16(b1) + uint16(b2)<<8
|
||||||
|
}
|
||||||
|
|
||||||
|
if frame.DataLength == 0 {
|
||||||
|
// The rest of the packet is data
|
||||||
|
frame.Data, err = ioutil.ReadAll(r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
frame.Data = make([]byte, frame.DataLength)
|
||||||
|
if _, err := r.Read(frame.Data); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return frame, nil
|
||||||
|
}
|
||||||
40
frame_test.go
Normal file
40
frame_test.go
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
package quic
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
|
||||||
|
. "github.com/onsi/ginkgo"
|
||||||
|
. "github.com/onsi/gomega"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = Describe("Frame", func() {
|
||||||
|
Context("when parsing", func() {
|
||||||
|
It("accepts sample frame", func() {
|
||||||
|
b := bytes.NewReader([]byte{0xa0, 0x1, 0x06, 0x00, 'f', 'o', 'o', 'b', 'a', 'r'})
|
||||||
|
frame, err := ParseStreamFrame(b)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(frame.FinBit).To(BeFalse())
|
||||||
|
Expect(frame.DataLengthPresent).To(BeTrue())
|
||||||
|
Expect(frame.OffsetLength).To(BeZero())
|
||||||
|
Expect(frame.StreamIDLength).To(Equal(uint8(1)))
|
||||||
|
Expect(frame.StreamID).To(Equal(uint32(1)))
|
||||||
|
Expect(frame.Offset).To(BeZero())
|
||||||
|
Expect(frame.DataLength).To(Equal(uint16(6)))
|
||||||
|
Expect(frame.Data).To(Equal([]byte("foobar")))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("accepts frame without datalength", func() {
|
||||||
|
b := bytes.NewReader([]byte{0x80, 0x1, 'f', 'o', 'o', 'b', 'a', 'r'})
|
||||||
|
frame, err := ParseStreamFrame(b)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(frame.FinBit).To(BeFalse())
|
||||||
|
Expect(frame.DataLengthPresent).To(BeFalse())
|
||||||
|
Expect(frame.OffsetLength).To(BeZero())
|
||||||
|
Expect(frame.StreamIDLength).To(Equal(uint8(1)))
|
||||||
|
Expect(frame.StreamID).To(Equal(uint32(1)))
|
||||||
|
Expect(frame.Offset).To(BeZero())
|
||||||
|
Expect(frame.DataLength).To(Equal(uint16(0)))
|
||||||
|
Expect(frame.Data).To(Equal([]byte("foobar")))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
Reference in New Issue
Block a user