implement stream frame writer

This commit is contained in:
Lucas Clemente
2016-04-10 19:42:12 +02:00
parent 3dc0209b84
commit 551d5798e4
3 changed files with 87 additions and 44 deletions

View File

@@ -8,14 +8,10 @@ import (
// A StreamFrame of QUIC
// TODO: Maybe remove unneeded stuff, e.g. lengths?
type StreamFrame struct {
FinBit bool
DataLengthPresent bool
OffsetLength uint8
StreamIDLength uint8
StreamID uint32
Offset uint64
DataLength uint16
Data []byte
FinBit bool
StreamID uint32
Offset uint64
Data []byte
}
// ParseStreamFrame reads a stream frame. The type byte must not have been read yet.
@@ -27,39 +23,40 @@ func ParseStreamFrame(r *bytes.Reader) (*StreamFrame, error) {
return nil, err
}
frame.FinBit = typeByte&0x40 > 0
frame.DataLengthPresent = typeByte&0x20 > 0
frame.OffsetLength = typeByte & 0x1C >> 2
if frame.OffsetLength != 0 {
frame.OffsetLength++
dataLenPresent := typeByte&0x20 > 0
offsetLen := typeByte & 0x1C >> 2
if offsetLen != 0 {
offsetLen++
}
frame.StreamIDLength = typeByte&0x03 + 1
streamIDLen := typeByte&0x03 + 1
sid, err := readUintN(r, frame.StreamIDLength)
sid, err := readUintN(r, streamIDLen)
if err != nil {
return nil, err
}
frame.StreamID = uint32(sid)
frame.Offset, err = readUintN(r, frame.OffsetLength)
frame.Offset, err = readUintN(r, offsetLen)
if err != nil {
return nil, err
}
if frame.DataLengthPresent {
frame.DataLength, err = readUint16(r)
var dataLen uint16
if dataLenPresent {
dataLen, err = readUint16(r)
if err != nil {
return nil, err
}
}
if frame.DataLength == 0 {
if dataLen == 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)
frame.Data = make([]byte, dataLen)
if _, err := r.Read(frame.Data); err != nil {
return nil, err
}
@@ -67,3 +64,23 @@ func ParseStreamFrame(r *bytes.Reader) (*StreamFrame, error) {
return frame, nil
}
// WriteStreamFrame writes a stream frame.
func WriteStreamFrame(b *bytes.Buffer, f *StreamFrame) {
typeByte := uint8(0x80)
if f.FinBit {
typeByte ^= 0x40
}
typeByte ^= 0x20
if f.Offset != 0 {
typeByte ^= 0x1c // TODO: Send shorter offset if possible
}
typeByte ^= 0x03 // TODO: Send shorter stream ID if possible
b.WriteByte(typeByte)
writeUint32(b, f.StreamID)
if f.Offset != 0 {
writeUint64(b, f.Offset)
}
writeUint16(b, uint16(len(f.Data)))
b.Write(f.Data)
}

View File

@@ -8,33 +8,48 @@ import (
)
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")))
Context("stream frames", 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.StreamID).To(Equal(uint32(1)))
Expect(frame.Offset).To(BeZero())
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.StreamID).To(Equal(uint32(1)))
Expect(frame.Offset).To(BeZero())
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")))
Context("when writing", func() {
It("writes sample frame", func() {
b := &bytes.Buffer{}
WriteStreamFrame(b, &StreamFrame{
StreamID: 1,
Data: []byte("foobar"),
})
Expect(b.Bytes()).To(Equal([]byte{0xa3, 0x1, 0, 0, 0, 0x06, 0x00, 'f', 'o', 'o', 'b', 'a', 'r'}))
})
It("writes offsets", func() {
b := &bytes.Buffer{}
WriteStreamFrame(b, &StreamFrame{
StreamID: 1,
Offset: 16,
Data: []byte("foobar"),
})
Expect(b.Bytes()).To(Equal([]byte{0xbf, 0x1, 0, 0, 0, 0x10, 0, 0, 0, 0, 0, 0, 0, 0x06, 0x00, 'f', 'o', 'o', 'b', 'a', 'r'}))
})
})
})
})

View File

@@ -47,6 +47,17 @@ func readUint16(b io.ByteReader) (uint16, error) {
return uint16(b1) + uint16(b2)<<8, nil
}
func writeUint64(b *bytes.Buffer, i uint64) {
b.WriteByte(uint8(i & 0xff))
b.WriteByte(uint8((i >> 8) & 0xff))
b.WriteByte(uint8((i >> 16) & 0xff))
b.WriteByte(uint8((i >> 24) & 0xff))
b.WriteByte(uint8((i >> 32) & 0xff))
b.WriteByte(uint8((i >> 40) & 0xff))
b.WriteByte(uint8((i >> 48) & 0xff))
b.WriteByte(uint8((i >> 56) & 0xff))
}
func writeUint32(b *bytes.Buffer, i uint32) {
b.WriteByte(uint8(i & 0xff))
b.WriteByte(uint8((i >> 8) & 0xff))