forked from quic-go/quic-go
implement parsing and writing of the DATAGRAM frames
This commit is contained in:
67
internal/wire/datagram_frame.go
Normal file
67
internal/wire/datagram_frame.go
Normal 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
|
||||
}
|
||||
98
internal/wire/datagram_frame_test.go
Normal file
98
internal/wire/datagram_frame_test.go
Normal 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)))
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
@@ -318,6 +318,7 @@ var _ = Describe("Frame parsing", func() {
|
||||
&PathResponseFrame{},
|
||||
&ConnectionCloseFrame{},
|
||||
&HandshakeDoneFrame{},
|
||||
&DatagramFrame{},
|
||||
}
|
||||
|
||||
var framesSerialized [][]byte
|
||||
|
||||
Reference in New Issue
Block a user