From cf104db6292ac2637075b59c7a1dafaafa77a728 Mon Sep 17 00:00:00 2001 From: Marten Seemann Date: Sat, 10 Nov 2018 09:46:57 +0700 Subject: [PATCH] implement parsing and writing of the NEW_TOKEN frame --- internal/wire/frame_parser.go | 3 +- internal/wire/frame_parser_test.go | 10 +++++ internal/wire/new_token_frame.go | 44 ++++++++++++++++++++ internal/wire/new_token_frame_test.go | 58 +++++++++++++++++++++++++++ session.go | 1 + 5 files changed, 115 insertions(+), 1 deletion(-) create mode 100644 internal/wire/new_token_frame.go create mode 100644 internal/wire/new_token_frame_test.go diff --git a/internal/wire/frame_parser.go b/internal/wire/frame_parser.go index bd4848b9b..5b1e501e0 100644 --- a/internal/wire/frame_parser.go +++ b/internal/wire/frame_parser.go @@ -44,7 +44,8 @@ func parseFrame(r *bytes.Reader, typeByte byte, v protocol.VersionNumber) (Frame frame, err = parseStopSendingFrame(r, v) case 0x6: frame, err = parseCryptoFrame(r, v) - // TODO: implement the NEW_TOKEN frame + case 0x7: + frame, err = parseNewTokenFrame(r, v) case 0x10: frame, err = parseMaxDataFrame(r, v) case 0x11: diff --git a/internal/wire/frame_parser_test.go b/internal/wire/frame_parser_test.go index b8f0abcb9..e3f138e72 100644 --- a/internal/wire/frame_parser_test.go +++ b/internal/wire/frame_parser_test.go @@ -85,6 +85,16 @@ var _ = Describe("Frame parsing", func() { Expect(frame).To(Equal(f)) }) + It("unpacks NEW_TOKEN frames", func() { + f := &NewTokenFrame{Token: []byte("foobar")} + err := f.Write(buf, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + frame, err := ParseNextFrame(bytes.NewReader(buf.Bytes()), versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + Expect(frame).ToNot(BeNil()) + Expect(frame).To(Equal(f)) + }) + It("unpacks STREAM frames", func() { f := &StreamFrame{ StreamID: 0x42, diff --git a/internal/wire/new_token_frame.go b/internal/wire/new_token_frame.go new file mode 100644 index 000000000..2cf6fce5e --- /dev/null +++ b/internal/wire/new_token_frame.go @@ -0,0 +1,44 @@ +package wire + +import ( + "bytes" + "io" + + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" +) + +// A NewTokenFrame is a NEW_TOKEN frame +type NewTokenFrame struct { + Token []byte +} + +func parseNewTokenFrame(r *bytes.Reader, _ protocol.VersionNumber) (*NewTokenFrame, error) { + if _, err := r.ReadByte(); err != nil { + return nil, err + } + tokenLen, err := utils.ReadVarInt(r) + if err != nil { + return nil, err + } + if uint64(r.Len()) < tokenLen { + return nil, io.EOF + } + token := make([]byte, int(tokenLen)) + if _, err := io.ReadFull(r, token); err != nil { + return nil, err + } + return &NewTokenFrame{Token: token}, nil +} + +func (f *NewTokenFrame) Write(b *bytes.Buffer, _ protocol.VersionNumber) error { + b.WriteByte(0x7) + utils.WriteVarInt(b, uint64(len(f.Token))) + b.Write(f.Token) + return nil +} + +// Length of a written frame +func (f *NewTokenFrame) Length(protocol.VersionNumber) protocol.ByteCount { + return 1 + utils.VarIntLen(uint64(len(f.Token))) + protocol.ByteCount(len(f.Token)) +} diff --git a/internal/wire/new_token_frame_test.go b/internal/wire/new_token_frame_test.go new file mode 100644 index 000000000..4c782256f --- /dev/null +++ b/internal/wire/new_token_frame_test.go @@ -0,0 +1,58 @@ +package wire + +import ( + "bytes" + + "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("NEW_TOKEN frame", func() { + Context("parsing", func() { + It("accepts a sample frame", func() { + token := "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua." + data := []byte{0x7} + data = append(data, encodeVarInt(uint64(len(token)))...) + data = append(data, token...) + b := bytes.NewReader(data) + f, err := parseNewTokenFrame(b, protocol.VersionWhatever) + Expect(err).ToNot(HaveOccurred()) + Expect(string(f.Token)).To(Equal(token)) + Expect(b.Len()).To(BeZero()) + }) + + It("errors on EOFs", func() { + token := "Lorem ipsum dolor sit amet, consectetur adipiscing elit" + data := []byte{0x7} + data = append(data, encodeVarInt(uint64(len(token)))...) + data = append(data, token...) + _, err := parseNewTokenFrame(bytes.NewReader(data), protocol.VersionWhatever) + Expect(err).NotTo(HaveOccurred()) + for i := range data { + _, err := parseNewTokenFrame(bytes.NewReader(data[0:i]), protocol.VersionWhatever) + Expect(err).To(HaveOccurred()) + } + }) + }) + + Context("writing", func() { + It("writes a sample frame", func() { + token := "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat." + f := &NewTokenFrame{Token: []byte(token)} + b := &bytes.Buffer{} + Expect(f.Write(b, protocol.VersionWhatever)).To(Succeed()) + expected := []byte{0x7} + expected = append(expected, encodeVarInt(uint64(len(token)))...) + expected = append(expected, token...) + Expect(b.Bytes()).To(Equal(expected)) + }) + + It("has the correct min length", func() { + frame := &NewTokenFrame{Token: []byte("foobar")} + Expect(frame.Length(protocol.VersionWhatever)).To(Equal(1 + utils.VarIntLen(6) + 6)) + }) + }) +}) diff --git a/session.go b/session.go index 2bf78e601..bfa4e279c 100644 --- a/session.go +++ b/session.go @@ -578,6 +578,7 @@ func (s *session) handleFrames(fs []wire.Frame, encLevel protocol.EncryptionLeve case *wire.PathResponseFrame: // since we don't send PATH_CHALLENGEs, we don't expect PATH_RESPONSEs err = errors.New("unexpected PATH_RESPONSE frame") + case *wire.NewTokenFrame: default: return errors.New("Session BUG: unexpected frame type") }