From 108e57458166b037887ea227a57d20a89bedad6b Mon Sep 17 00:00:00 2001 From: Marten Seemann Date: Sun, 22 Apr 2018 18:12:56 +0900 Subject: [PATCH] implement parsing and writing of the PATH_RESPONSE frame --- internal/wire/frame_parser.go | 5 +++ internal/wire/frame_parser_test.go | 16 +++++++- internal/wire/path_response_frame.go | 39 +++++++++++++++++++ internal/wire/path_response_frame_test.go | 47 +++++++++++++++++++++++ 4 files changed, 105 insertions(+), 2 deletions(-) create mode 100644 internal/wire/path_response_frame.go create mode 100644 internal/wire/path_response_frame_test.go diff --git a/internal/wire/frame_parser.go b/internal/wire/frame_parser.go index b4409532d..7318d8841 100644 --- a/internal/wire/frame_parser.go +++ b/internal/wire/frame_parser.go @@ -95,6 +95,11 @@ func parseIETFFrame(r *bytes.Reader, typeByte byte, v protocol.VersionNumber) (F if err != nil { err = qerr.Error(qerr.InvalidFrameData, err.Error()) } + case 0xf: + frame, err = parsePathResponseFrame(r, v) + if err != nil { + err = qerr.Error(qerr.InvalidFrameData, err.Error()) + } default: err = qerr.Error(qerr.InvalidFrameData, fmt.Sprintf("unknown type byte 0x%x", typeByte)) } diff --git a/internal/wire/frame_parser_test.go b/internal/wire/frame_parser_test.go index c081b7156..525589e9d 100644 --- a/internal/wire/frame_parser_test.go +++ b/internal/wire/frame_parser_test.go @@ -300,9 +300,20 @@ var _ = Describe("Frame parsing", func() { Expect(frame.(*PathChallengeFrame).Data).To(Equal([8]byte{1, 2, 3, 4, 5, 6, 7, 8})) }) + It("unpacks PATH_RESPONSE frames", func() { + f := &PathResponseFrame{Data: [8]byte{1, 2, 3, 4, 5, 6, 7, 8}} + err := f.Write(buf, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + frame, err := ParseNextFrame(bytes.NewReader(buf.Bytes()), nil, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + Expect(frame).ToNot(BeNil()) + Expect(frame).To(BeAssignableToTypeOf(f)) + Expect(frame.(*PathResponseFrame).Data).To(Equal([8]byte{1, 2, 3, 4, 5, 6, 7, 8})) + }) + It("errors on invalid type", func() { - _, err := ParseNextFrame(bytes.NewReader([]byte{0xf}), nil, versionIETFFrames) - Expect(err).To(MatchError("InvalidFrameData: unknown type byte 0xf")) + _, err := ParseNextFrame(bytes.NewReader([]byte{0x42}), nil, versionIETFFrames) + Expect(err).To(MatchError("InvalidFrameData: unknown type byte 0x42")) }) It("errors on invalid frames", func() { @@ -318,6 +329,7 @@ var _ = Describe("Frame parsing", func() { 0x0c: qerr.InvalidFrameData, 0x0d: qerr.InvalidAckData, 0x0e: qerr.InvalidFrameData, + 0x0f: qerr.InvalidFrameData, 0x10: qerr.InvalidStreamData, } { _, err := ParseNextFrame(bytes.NewReader([]byte{b}), nil, versionIETFFrames) diff --git a/internal/wire/path_response_frame.go b/internal/wire/path_response_frame.go new file mode 100644 index 000000000..2ab2fcda9 --- /dev/null +++ b/internal/wire/path_response_frame.go @@ -0,0 +1,39 @@ +package wire + +import ( + "bytes" + "io" + + "github.com/lucas-clemente/quic-go/internal/protocol" +) + +// A PathResponseFrame is a PATH_RESPONSE frame +type PathResponseFrame struct { + Data [8]byte +} + +func parsePathResponseFrame(r *bytes.Reader, version protocol.VersionNumber) (*PathResponseFrame, error) { + if _, err := r.ReadByte(); err != nil { + return nil, err + } + frame := &PathResponseFrame{} + if _, err := io.ReadFull(r, frame.Data[:]); err != nil { + if err == io.ErrUnexpectedEOF { + return nil, io.EOF + } + return nil, err + } + return frame, nil +} + +func (f *PathResponseFrame) Write(b *bytes.Buffer, _ protocol.VersionNumber) error { + typeByte := uint8(0x0f) + b.WriteByte(typeByte) + b.Write(f.Data[:]) + return nil +} + +// Length of a written frame +func (f *PathResponseFrame) Length(_ protocol.VersionNumber) protocol.ByteCount { + return 1 + 8 +} diff --git a/internal/wire/path_response_frame_test.go b/internal/wire/path_response_frame_test.go new file mode 100644 index 000000000..14e45bed8 --- /dev/null +++ b/internal/wire/path_response_frame_test.go @@ -0,0 +1,47 @@ +package wire + +import ( + "bytes" + "io" + + "github.com/lucas-clemente/quic-go/internal/protocol" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("PATH_RESPONSE frame", func() { + Context("when parsing", func() { + It("accepts sample frame", func() { + b := bytes.NewReader([]byte{0x0f, 1, 2, 3, 4, 5, 6, 7, 8}) + f, err := parsePathResponseFrame(b, protocol.VersionWhatever) + Expect(err).ToNot(HaveOccurred()) + Expect(b.Len()).To(BeZero()) + Expect(f.Data).To(Equal([8]byte{1, 2, 3, 4, 5, 6, 7, 8})) + }) + + It("errors on EOFs", func() { + data := []byte{0x0f, 1, 2, 3, 4, 5, 6, 7, 8} + _, err := parsePathResponseFrame(bytes.NewReader(data), versionIETFFrames) + Expect(err).NotTo(HaveOccurred()) + for i := range data { + _, err := parsePathResponseFrame(bytes.NewReader(data[0:i]), versionIETFFrames) + Expect(err).To(MatchError(io.EOF)) + } + }) + }) + + Context("when writing", func() { + It("writes a sample frame", func() { + b := &bytes.Buffer{} + frame := PathResponseFrame{Data: [8]byte{0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0x13, 0x37}} + err := frame.Write(b, protocol.VersionWhatever) + Expect(err).ToNot(HaveOccurred()) + Expect(b.Bytes()).To(Equal([]byte{0x0f, 0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0x13, 0x37})) + }) + + It("has the correct min length", func() { + frame := PathResponseFrame{} + Expect(frame.Length(protocol.VersionWhatever)).To(Equal(protocol.ByteCount(9))) + }) + }) +})