route/vendor/github.com/lucas-clemente/quic-go/stream_frame_sorter_test.go

596 lines
18 KiB
Go

package quic
import (
"bytes"
"github.com/lucas-clemente/quic-go/internal/protocol"
"github.com/lucas-clemente/quic-go/internal/utils"
"github.com/lucas-clemente/quic-go/internal/wire"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
var _ = Describe("StreamFrame sorter", func() {
var s *streamFrameSorter
checkGaps := func(expectedGaps []utils.ByteInterval) {
Expect(s.gaps.Len()).To(Equal(len(expectedGaps)))
var i int
for gap := s.gaps.Front(); gap != nil; gap = gap.Next() {
Expect(gap.Value).To(Equal(expectedGaps[i]))
i++
}
}
BeforeEach(func() {
s = newStreamFrameSorter()
})
It("head returns nil when empty", func() {
Expect(s.Head()).To(BeNil())
})
Context("Push", func() {
It("inserts and pops a single frame", func() {
f := &wire.StreamFrame{
Offset: 0,
Data: []byte("foobar"),
}
err := s.Push(f)
Expect(err).ToNot(HaveOccurred())
Expect(s.Head()).To(Equal(f))
Expect(s.Pop()).To(Equal(f))
Expect(s.Head()).To(BeNil())
})
It("inserts and pops two consecutive frame", func() {
f1 := &wire.StreamFrame{
Offset: 0,
Data: []byte("foobar"),
}
f2 := &wire.StreamFrame{
Offset: 6,
Data: []byte("foobar2"),
}
err := s.Push(f1)
Expect(err).ToNot(HaveOccurred())
err = s.Push(f2)
Expect(err).ToNot(HaveOccurred())
Expect(s.Pop()).To(Equal(f1))
Expect(s.Pop()).To(Equal(f2))
Expect(s.Head()).To(BeNil())
})
It("rejects empty frames", func() {
f := &wire.StreamFrame{}
err := s.Push(f)
Expect(err).To(MatchError(errEmptyStreamData))
})
Context("FinBit handling", func() {
It("saves a FinBit frame at offset 0", func() {
f := &wire.StreamFrame{
Offset: 0,
FinBit: true,
}
err := s.Push(f)
Expect(err).ToNot(HaveOccurred())
Expect(s.Head()).To(Equal(f))
})
It("sets the FinBit if a stream is closed after receiving some data", func() {
f1 := &wire.StreamFrame{
Offset: 0,
Data: []byte("foobar"),
}
err := s.Push(f1)
Expect(err).ToNot(HaveOccurred())
f2 := &wire.StreamFrame{
Offset: 6,
FinBit: true,
}
err = s.Push(f2)
Expect(err).ToNot(HaveOccurred())
Expect(s.Pop()).To(Equal(f1))
Expect(s.Pop()).To(Equal(f2))
})
})
Context("Gap handling", func() {
It("finds the first gap", func() {
f := &wire.StreamFrame{
Offset: 10,
Data: []byte("foobar"),
}
err := s.Push(f)
Expect(err).ToNot(HaveOccurred())
checkGaps([]utils.ByteInterval{
{Start: 0, End: 10},
{Start: 16, End: protocol.MaxByteCount},
})
})
It("correctly sets the first gap for a frame with offset 0", func() {
f := &wire.StreamFrame{
Offset: 0,
Data: []byte("foobar"),
}
err := s.Push(f)
Expect(err).ToNot(HaveOccurred())
checkGaps([]utils.ByteInterval{
{Start: 6, End: protocol.MaxByteCount},
})
})
It("finds the two gaps", func() {
f1 := &wire.StreamFrame{
Offset: 10,
Data: []byte("foobar"),
}
err := s.Push(f1)
Expect(err).ToNot(HaveOccurred())
f2 := &wire.StreamFrame{
Offset: 20,
Data: []byte("foobar"),
}
err = s.Push(f2)
Expect(err).ToNot(HaveOccurred())
checkGaps([]utils.ByteInterval{
{Start: 0, End: 10},
{Start: 16, End: 20},
{Start: 26, End: protocol.MaxByteCount},
})
})
It("finds the two gaps in reverse order", func() {
f1 := &wire.StreamFrame{
Offset: 20,
Data: []byte("foobar"),
}
err := s.Push(f1)
Expect(err).ToNot(HaveOccurred())
f2 := &wire.StreamFrame{
Offset: 10,
Data: []byte("foobar"),
}
err = s.Push(f2)
Expect(err).ToNot(HaveOccurred())
checkGaps([]utils.ByteInterval{
{Start: 0, End: 10},
{Start: 16, End: 20},
{Start: 26, End: protocol.MaxByteCount},
})
})
It("shrinks a gap when it is partially filled", func() {
f1 := &wire.StreamFrame{
Offset: 10,
Data: []byte("test"),
}
err := s.Push(f1)
Expect(err).ToNot(HaveOccurred())
f2 := &wire.StreamFrame{
Offset: 4,
Data: []byte("foobar"),
}
err = s.Push(f2)
Expect(err).ToNot(HaveOccurred())
checkGaps([]utils.ByteInterval{
{Start: 0, End: 4},
{Start: 14, End: protocol.MaxByteCount},
})
})
It("deletes a gap at the beginning, when it is filled", func() {
f1 := &wire.StreamFrame{
Offset: 6,
Data: []byte("test"),
}
err := s.Push(f1)
Expect(err).ToNot(HaveOccurred())
f2 := &wire.StreamFrame{
Offset: 0,
Data: []byte("foobar"),
}
err = s.Push(f2)
Expect(err).ToNot(HaveOccurred())
checkGaps([]utils.ByteInterval{
{Start: 10, End: protocol.MaxByteCount},
})
})
It("deletes a gap in the middle, when it is filled", func() {
f1 := &wire.StreamFrame{
Offset: 0,
Data: []byte("test"),
}
err := s.Push(f1)
Expect(err).ToNot(HaveOccurred())
f2 := &wire.StreamFrame{
Offset: 10,
Data: []byte("test2"),
}
err = s.Push(f2)
Expect(err).ToNot(HaveOccurred())
f3 := &wire.StreamFrame{
Offset: 4,
Data: []byte("foobar"),
}
err = s.Push(f3)
Expect(err).ToNot(HaveOccurred())
Expect(s.queuedFrames).To(HaveLen(3))
checkGaps([]utils.ByteInterval{
{Start: 15, End: protocol.MaxByteCount},
})
})
It("splits a gap into two", func() {
f1 := &wire.StreamFrame{
Offset: 100,
Data: []byte("test"),
}
err := s.Push(f1)
Expect(err).ToNot(HaveOccurred())
f2 := &wire.StreamFrame{
Offset: 50,
Data: []byte("foobar"),
}
err = s.Push(f2)
Expect(err).ToNot(HaveOccurred())
Expect(s.queuedFrames).To(HaveLen(2))
checkGaps([]utils.ByteInterval{
{Start: 0, End: 50},
{Start: 56, End: 100},
{Start: 104, End: protocol.MaxByteCount},
})
})
Context("Overlapping Stream Data detection", func() {
// create gaps: 0-5, 10-15, 20-25, 30-inf
BeforeEach(func() {
err := s.Push(&wire.StreamFrame{Offset: 5, Data: []byte("12345")})
Expect(err).ToNot(HaveOccurred())
err = s.Push(&wire.StreamFrame{Offset: 15, Data: []byte("12345")})
Expect(err).ToNot(HaveOccurred())
err = s.Push(&wire.StreamFrame{Offset: 25, Data: []byte("12345")})
Expect(err).ToNot(HaveOccurred())
checkGaps([]utils.ByteInterval{
{Start: 0, End: 5},
{Start: 10, End: 15},
{Start: 20, End: 25},
{Start: 30, End: protocol.MaxByteCount},
})
})
It("cuts a frame with offset 0 that overlaps at the end", func() {
f := &wire.StreamFrame{
Offset: 0,
Data: []byte("foobar"),
}
err := s.Push(f)
Expect(err).ToNot(HaveOccurred())
Expect(s.queuedFrames).To(HaveKey(protocol.ByteCount(0)))
Expect(s.queuedFrames[0].Data).To(Equal([]byte("fooba")))
Expect(s.queuedFrames[0].Data).To(HaveCap(5))
checkGaps([]utils.ByteInterval{
{Start: 10, End: 15},
{Start: 20, End: 25},
{Start: 30, End: protocol.MaxByteCount},
})
})
It("cuts a frame that overlaps at the end", func() {
// 4 to 7
f := &wire.StreamFrame{
Offset: 4,
Data: []byte("foo"),
}
err := s.Push(f)
Expect(err).ToNot(HaveOccurred())
Expect(s.queuedFrames).To(HaveKey(protocol.ByteCount(4)))
Expect(s.queuedFrames[4].Data).To(Equal([]byte("f")))
Expect(s.queuedFrames[4].Data).To(HaveCap(1))
checkGaps([]utils.ByteInterval{
{Start: 0, End: 4},
{Start: 10, End: 15},
{Start: 20, End: 25},
{Start: 30, End: protocol.MaxByteCount},
})
})
It("cuts a frame that completely fills a gap, but overlaps at the end", func() {
// 10 to 16
f := &wire.StreamFrame{
Offset: 10,
Data: []byte("foobar"),
}
err := s.Push(f)
Expect(err).ToNot(HaveOccurred())
Expect(s.queuedFrames).To(HaveKey(protocol.ByteCount(10)))
Expect(s.queuedFrames[10].Data).To(Equal([]byte("fooba")))
Expect(s.queuedFrames[10].Data).To(HaveCap(5))
checkGaps([]utils.ByteInterval{
{Start: 0, End: 5},
{Start: 20, End: 25},
{Start: 30, End: protocol.MaxByteCount},
})
})
It("cuts a frame that overlaps at the beginning", func() {
// 8 to 14
f := &wire.StreamFrame{
Offset: 8,
Data: []byte("foobar"),
}
err := s.Push(f)
Expect(err).ToNot(HaveOccurred())
Expect(s.queuedFrames).ToNot(HaveKey(protocol.ByteCount(8)))
Expect(s.queuedFrames).To(HaveKey(protocol.ByteCount(10)))
Expect(s.queuedFrames[10].Data).To(Equal([]byte("obar")))
Expect(s.queuedFrames[10].Data).To(HaveCap(4))
checkGaps([]utils.ByteInterval{
{Start: 0, End: 5},
{Start: 14, End: 15},
{Start: 20, End: 25},
{Start: 30, End: protocol.MaxByteCount},
})
})
It("processes a frame that overlaps at the beginning and at the end, starting in a gap", func() {
// 2 to 12
f := &wire.StreamFrame{
Offset: 2,
Data: []byte("1234567890"),
}
err := s.Push(f)
Expect(err).ToNot(HaveOccurred())
Expect(s.queuedFrames).ToNot(HaveKey(protocol.ByteCount(5)))
Expect(s.queuedFrames).To(HaveKey(protocol.ByteCount(2)))
Expect(s.queuedFrames[2].Data).To(Equal([]byte("1234567890")))
checkGaps([]utils.ByteInterval{
{Start: 0, End: 2},
{Start: 12, End: 15},
{Start: 20, End: 25},
{Start: 30, End: protocol.MaxByteCount},
})
})
It("processes a frame that overlaps at the beginning and at the end, starting in a gap, ending in data", func() {
// 2 to 17
f := &wire.StreamFrame{
Offset: 2,
Data: []byte("123456789012345"),
}
err := s.Push(f)
Expect(err).ToNot(HaveOccurred())
Expect(s.queuedFrames).ToNot(HaveKey(protocol.ByteCount(5)))
Expect(s.queuedFrames).To(HaveKey(protocol.ByteCount(2)))
Expect(s.queuedFrames[2].Data).To(Equal([]byte("1234567890123")))
Expect(s.queuedFrames[2].Data).To(HaveCap(13))
checkGaps([]utils.ByteInterval{
{Start: 0, End: 2},
{Start: 20, End: 25},
{Start: 30, End: protocol.MaxByteCount},
})
})
It("processes a frame that overlaps at the beginning and at the end, starting in a gap, ending in data", func() {
// 5 to 22
f := &wire.StreamFrame{
Offset: 5,
Data: []byte("12345678901234567"),
}
err := s.Push(f)
Expect(err).ToNot(HaveOccurred())
Expect(s.queuedFrames).To(HaveKey(protocol.ByteCount(5)))
Expect(s.queuedFrames).ToNot(HaveKey(protocol.ByteCount(15)))
Expect(s.queuedFrames[10].Data).To(Equal([]byte("678901234567")))
checkGaps([]utils.ByteInterval{
{Start: 0, End: 5},
{Start: 22, End: 25},
{Start: 30, End: protocol.MaxByteCount},
})
})
It("processes a frame that closes multiple gaps", func() {
// 2 to 27
f := &wire.StreamFrame{
Offset: 2,
Data: bytes.Repeat([]byte{'e'}, 25),
}
err := s.Push(f)
Expect(err).ToNot(HaveOccurred())
Expect(s.queuedFrames).ToNot(HaveKey(protocol.ByteCount(5)))
Expect(s.queuedFrames).ToNot(HaveKey(protocol.ByteCount(15)))
Expect(s.queuedFrames).To(HaveKey(protocol.ByteCount(25)))
Expect(s.queuedFrames).To(HaveKey(protocol.ByteCount(2)))
Expect(s.queuedFrames[2].Data).To(Equal(bytes.Repeat([]byte{'e'}, 23)))
Expect(s.queuedFrames[2].Data).To(HaveCap(23))
checkGaps([]utils.ByteInterval{
{Start: 0, End: 2},
{Start: 30, End: protocol.MaxByteCount},
})
})
It("processes a frame that closes multiple gaps", func() {
// 5 to 27
f := &wire.StreamFrame{
Offset: 5,
Data: bytes.Repeat([]byte{'d'}, 22),
}
err := s.Push(f)
Expect(err).ToNot(HaveOccurred())
Expect(s.queuedFrames).To(HaveKey(protocol.ByteCount(5)))
Expect(s.queuedFrames).ToNot(HaveKey(protocol.ByteCount(15)))
Expect(s.queuedFrames).To(HaveKey(protocol.ByteCount(25)))
Expect(s.queuedFrames).To(HaveKey(protocol.ByteCount(10)))
Expect(s.queuedFrames[10].Data).To(Equal(bytes.Repeat([]byte{'d'}, 15)))
Expect(s.queuedFrames[10].Data).To(HaveCap(15))
checkGaps([]utils.ByteInterval{
{Start: 0, End: 5},
{Start: 30, End: protocol.MaxByteCount},
})
})
It("processes a frame that covers multiple gaps and ends at the end of a gap", func() {
// 1 to 15
f := &wire.StreamFrame{
Offset: 1,
Data: bytes.Repeat([]byte{'f'}, 14),
}
err := s.Push(f)
Expect(err).ToNot(HaveOccurred())
Expect(s.queuedFrames).To(HaveKey(protocol.ByteCount(1)))
Expect(s.queuedFrames).To(HaveKey(protocol.ByteCount(15)))
Expect(s.queuedFrames).ToNot(HaveKey(protocol.ByteCount(5)))
Expect(s.queuedFrames[1].Data).To(Equal(f.Data))
checkGaps([]utils.ByteInterval{
{Start: 0, End: 1},
{Start: 20, End: 25},
{Start: 30, End: protocol.MaxByteCount},
})
})
It("processes a frame that closes all gaps (except for the last one)", func() {
// 0 to 32
f := &wire.StreamFrame{
Offset: 0,
Data: bytes.Repeat([]byte{'f'}, 32),
}
err := s.Push(f)
Expect(err).ToNot(HaveOccurred())
Expect(s.queuedFrames).To(HaveLen(1))
Expect(s.queuedFrames).To(HaveKey(protocol.ByteCount(0)))
Expect(s.queuedFrames[0].Data).To(Equal(f.Data))
checkGaps([]utils.ByteInterval{
{Start: 32, End: protocol.MaxByteCount},
})
})
It("cuts a frame that overlaps at the beginning and at the end, starting in data already received", func() {
// 8 to 17
f := &wire.StreamFrame{
Offset: 8,
Data: []byte("123456789"),
}
err := s.Push(f)
Expect(err).ToNot(HaveOccurred())
Expect(s.queuedFrames).ToNot(HaveKey(protocol.ByteCount(8)))
Expect(s.queuedFrames).To(HaveKey(protocol.ByteCount(10)))
Expect(s.queuedFrames[10].Data).To(Equal([]byte("34567")))
Expect(s.queuedFrames[10].Data).To(HaveCap(5))
checkGaps([]utils.ByteInterval{
{Start: 0, End: 5},
{Start: 20, End: 25},
{Start: 30, End: protocol.MaxByteCount},
})
})
It("cuts a frame that completely covers two gaps", func() {
// 10 to 20
f := &wire.StreamFrame{
Offset: 10,
Data: []byte("1234567890"),
}
err := s.Push(f)
Expect(err).ToNot(HaveOccurred())
Expect(s.queuedFrames).To(HaveKey(protocol.ByteCount(10)))
Expect(s.queuedFrames[10].Data).To(Equal([]byte("12345")))
Expect(s.queuedFrames[10].Data).To(HaveCap(5))
checkGaps([]utils.ByteInterval{
{Start: 0, End: 5},
{Start: 20, End: 25},
{Start: 30, End: protocol.MaxByteCount},
})
})
})
Context("duplicate data", func() {
expectedGaps := []utils.ByteInterval{
{Start: 5, End: 10},
{Start: 15, End: protocol.MaxByteCount},
}
BeforeEach(func() {
// create gaps: 5-10, 15-inf
err := s.Push(&wire.StreamFrame{Offset: 0, Data: []byte("12345")})
Expect(err).ToNot(HaveOccurred())
err = s.Push(&wire.StreamFrame{Offset: 10, Data: []byte("12345")})
Expect(err).ToNot(HaveOccurred())
checkGaps(expectedGaps)
})
AfterEach(func() {
// check that the gaps were not modified
checkGaps(expectedGaps)
})
It("does not modify data when receiving a duplicate", func() {
err := s.Push(&wire.StreamFrame{Offset: 0, Data: []byte("fffff")})
Expect(err).To(MatchError(errDuplicateStreamData))
Expect(s.queuedFrames[0].Data).ToNot(Equal([]byte("fffff")))
})
It("detects a duplicate frame that is smaller than the original, starting at the beginning", func() {
// 10 to 12
err := s.Push(&wire.StreamFrame{Offset: 10, Data: []byte("12")})
Expect(err).To(MatchError(errDuplicateStreamData))
Expect(s.queuedFrames[10].Data).To(HaveLen(5))
})
It("detects a duplicate frame that is smaller than the original, somewhere in the middle", func() {
// 1 to 4
err := s.Push(&wire.StreamFrame{Offset: 1, Data: []byte("123")})
Expect(err).To(MatchError(errDuplicateStreamData))
Expect(s.queuedFrames[0].Data).To(HaveLen(5))
Expect(s.queuedFrames).ToNot(HaveKey(protocol.ByteCount(1)))
})
It("detects a duplicate frame that is smaller than the original, somewhere in the middle in the last block", func() {
// 11 to 14
err := s.Push(&wire.StreamFrame{Offset: 11, Data: []byte("123")})
Expect(err).To(MatchError(errDuplicateStreamData))
Expect(s.queuedFrames[10].Data).To(HaveLen(5))
Expect(s.queuedFrames).ToNot(HaveKey(protocol.ByteCount(11)))
})
It("detects a duplicate frame that is smaller than the original, with aligned end in the last block", func() {
// 11 to 14
err := s.Push(&wire.StreamFrame{Offset: 11, Data: []byte("1234")})
Expect(err).To(MatchError(errDuplicateStreamData))
Expect(s.queuedFrames[10].Data).To(HaveLen(5))
Expect(s.queuedFrames).ToNot(HaveKey(protocol.ByteCount(11)))
})
It("detects a duplicate frame that is smaller than the original, with aligned end", func() {
// 3 to 5
err := s.Push(&wire.StreamFrame{Offset: 3, Data: []byte("12")})
Expect(err).To(MatchError(errDuplicateStreamData))
Expect(s.queuedFrames[0].Data).To(HaveLen(5))
Expect(s.queuedFrames).ToNot(HaveKey(protocol.ByteCount(3)))
})
})
Context("DoS protection", func() {
It("errors when too many gaps are created", func() {
for i := 0; i < protocol.MaxStreamFrameSorterGaps; i++ {
f := &wire.StreamFrame{
Data: []byte("foobar"),
Offset: protocol.ByteCount(i * 7),
}
err := s.Push(f)
Expect(err).ToNot(HaveOccurred())
}
Expect(s.gaps.Len()).To(Equal(protocol.MaxStreamFrameSorterGaps))
f := &wire.StreamFrame{
Data: []byte("foobar"),
Offset: protocol.ByteCount(protocol.MaxStreamFrameSorterGaps*7) + 100,
}
err := s.Push(f)
Expect(err).To(MatchError(errTooManyGapsInReceivedStreamData))
})
})
})
})
})