implement parsing of stream frames

This commit is contained in:
Lucas Clemente
2016-04-08 12:17:47 +02:00
parent 1f30d50418
commit 981b061c0c
2 changed files with 112 additions and 0 deletions

72
frame.go Normal file
View 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
View 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")))
})
})
})