implement parsing and writing of the DATAGRAM frames

This commit is contained in:
Marten Seemann
2019-10-05 18:47:57 +02:00
parent deacefdd34
commit eefd2b73f7
4 changed files with 168 additions and 0 deletions

View File

@@ -0,0 +1,67 @@
package wire
import (
"bytes"
"io"
"github.com/lucas-clemente/quic-go/internal/protocol"
"github.com/lucas-clemente/quic-go/internal/utils"
)
// A DatagramFrame is a DATAGRAM frame
type DatagramFrame struct {
DataLenPresent bool
Data []byte
}
func parseDatagramFrame(r *bytes.Reader, _ protocol.VersionNumber) (*DatagramFrame, error) {
typeByte, err := r.ReadByte()
if err != nil {
return nil, err
}
f := &DatagramFrame{}
f.DataLenPresent = typeByte&0x1 > 0
var length uint64
if f.DataLenPresent {
var err error
len, err := utils.ReadVarInt(r)
if err != nil {
return nil, err
}
if len > uint64(r.Len()) {
return nil, io.EOF
}
length = len
} else {
length = uint64(r.Len())
}
f.Data = make([]byte, length)
if _, err := io.ReadFull(r, f.Data); err != nil {
return nil, err
}
return f, nil
}
func (f *DatagramFrame) Write(b *bytes.Buffer, _ protocol.VersionNumber) error {
typeByte := uint8(0x30)
if f.DataLenPresent {
typeByte ^= 0x1
}
b.WriteByte(typeByte)
if f.DataLenPresent {
utils.WriteVarInt(b, uint64(len(f.Data)))
}
b.Write(f.Data)
return nil
}
// Length of a written frame
func (f *DatagramFrame) Length(_ protocol.VersionNumber) protocol.ByteCount {
length := 1 + protocol.ByteCount(len(f.Data))
if f.DataLenPresent {
length += utils.VarIntLen(uint64(len(f.Data)))
}
return length
}

View File

@@ -0,0 +1,98 @@
package wire
import (
"bytes"
"io"
"github.com/lucas-clemente/quic-go/internal/protocol"
"github.com/lucas-clemente/quic-go/internal/utils"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
var _ = Describe("STREAM frame", func() {
Context("when parsing", func() {
It("parses a frame containing a length", func() {
data := []byte{0x30 ^ 0x1}
data = append(data, encodeVarInt(0x6)...) // length
data = append(data, []byte("foobar")...)
r := bytes.NewReader(data)
frame, err := parseDatagramFrame(r, versionIETFFrames)
Expect(err).ToNot(HaveOccurred())
Expect(frame.Data).To(Equal([]byte("foobar")))
Expect(frame.DataLenPresent).To(BeTrue())
Expect(r.Len()).To(BeZero())
})
It("parses a frame without length", func() {
data := []byte{0x30}
data = append(data, []byte("Lorem ipsum dolor sit amet")...)
r := bytes.NewReader(data)
frame, err := parseDatagramFrame(r, versionIETFFrames)
Expect(err).ToNot(HaveOccurred())
Expect(frame.Data).To(Equal([]byte("Lorem ipsum dolor sit amet")))
Expect(frame.DataLenPresent).To(BeFalse())
Expect(r.Len()).To(BeZero())
})
It("errors when the length is longer than the rest of the frame", func() {
data := []byte{0x30 ^ 0x1}
data = append(data, encodeVarInt(0x6)...) // length
data = append(data, []byte("fooba")...)
r := bytes.NewReader(data)
_, err := parseDatagramFrame(r, versionIETFFrames)
Expect(err).To(MatchError(io.EOF))
})
It("errors on EOFs", func() {
data := []byte{0x30 ^ 0x1}
data = append(data, encodeVarInt(6)...) // length
data = append(data, []byte("foobar")...)
_, err := parseDatagramFrame(bytes.NewReader(data), versionIETFFrames)
Expect(err).NotTo(HaveOccurred())
for i := range data {
_, err := parseDatagramFrame(bytes.NewReader(data[0:i]), versionIETFFrames)
Expect(err).To(MatchError(io.EOF))
}
})
})
Context("when writing", func() {
It("writes a frame with length", func() {
f := &DatagramFrame{
DataLenPresent: true,
Data: []byte("foobar"),
}
buf := &bytes.Buffer{}
Expect(f.Write(buf, versionIETFFrames)).To(Succeed())
expected := []byte{0x30 ^ 0x1}
expected = append(expected, encodeVarInt(0x6)...)
expected = append(expected, []byte("foobar")...)
Expect(buf.Bytes()).To(Equal(expected))
})
It("writes a frame without length", func() {
f := &DatagramFrame{Data: []byte("Lorem ipsum")}
buf := &bytes.Buffer{}
Expect(f.Write(buf, versionIETFFrames)).To(Succeed())
expected := []byte{0x30}
expected = append(expected, []byte("Lorem ipsum")...)
Expect(buf.Bytes()).To(Equal(expected))
})
})
Context("length", func() {
It("has the right length for a frame with length", func() {
f := &DatagramFrame{
DataLenPresent: true,
Data: []byte("foobar"),
}
Expect(f.Length(versionIETFFrames)).To(Equal(1 + utils.VarIntLen(6) + 6))
})
It("has the right length for a frame without length", func() {
f := &DatagramFrame{Data: []byte("foobar")}
Expect(f.Length(versionIETFFrames)).To(Equal(protocol.ByteCount(1 + 6)))
})
})
})

View File

@@ -87,6 +87,8 @@ func (p *frameParser) parseFrame(r *bytes.Reader, typeByte byte, encLevel protoc
frame, err = parseConnectionCloseFrame(r, p.version)
case 0x1e:
frame, err = parseHandshakeDoneFrame(r, p.version)
case 0x30, 0x31:
frame, err = parseDatagramFrame(r, p.version)
default:
err = errors.New("unknown frame type")
}

View File

@@ -318,6 +318,7 @@ var _ = Describe("Frame parsing", func() {
&PathResponseFrame{},
&ConnectionCloseFrame{},
&HandshakeDoneFrame{},
&DatagramFrame{},
}
var framesSerialized [][]byte