mirror of
https://github.com/refraction-networking/uquic.git
synced 2025-04-03 20:27:35 +03:00
563 lines
21 KiB
Go
563 lines
21 KiB
Go
package quic
|
|
|
|
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("frame sorter", func() {
|
|
var s *frameSorter
|
|
|
|
checkGaps := func(expectedGaps []utils.ByteInterval) {
|
|
ExpectWithOffset(1, s.gaps.Len()).To(Equal(len(expectedGaps)))
|
|
var i int
|
|
for gap := s.gaps.Front(); gap != nil; gap = gap.Next() {
|
|
ExpectWithOffset(1, gap.Value).To(Equal(expectedGaps[i]))
|
|
i++
|
|
}
|
|
}
|
|
|
|
getCallback := func() (func(), *bool) {
|
|
var called bool
|
|
return func() { called = true }, &called
|
|
}
|
|
|
|
checkCallback := func(cb func(), called *bool) {
|
|
ExpectWithOffset(1, cb).ToNot(BeNil())
|
|
ExpectWithOffset(1, *called).To(BeFalse())
|
|
cb()
|
|
ExpectWithOffset(1, *called).To(BeTrue())
|
|
}
|
|
|
|
BeforeEach(func() {
|
|
s = newFrameSorter()
|
|
_ = checkGaps
|
|
})
|
|
|
|
It("returns nil when empty", func() {
|
|
_, data, doneCb := s.Pop()
|
|
Expect(data).To(BeNil())
|
|
Expect(doneCb).To(BeNil())
|
|
})
|
|
|
|
Context("Push", func() {
|
|
It("inserts and pops a single frame", func() {
|
|
cb, called := getCallback()
|
|
Expect(s.Push([]byte("foobar"), 0, cb)).To(Succeed())
|
|
offset, data, doneCb := s.Pop()
|
|
Expect(offset).To(BeZero())
|
|
Expect(data).To(Equal([]byte("foobar")))
|
|
checkCallback(doneCb, called)
|
|
offset, data, doneCb = s.Pop()
|
|
Expect(offset).To(Equal(protocol.ByteCount(6)))
|
|
Expect(data).To(BeNil())
|
|
Expect(doneCb).To(BeNil())
|
|
})
|
|
|
|
It("inserts and pops two consecutive frame", func() {
|
|
cb1, called1 := getCallback()
|
|
cb2, called2 := getCallback()
|
|
Expect(s.Push([]byte("bar"), 3, cb2)).To(Succeed())
|
|
Expect(s.Push([]byte("foo"), 0, cb1)).To(Succeed())
|
|
offset, data, doneCb := s.Pop()
|
|
Expect(offset).To(BeZero())
|
|
Expect(data).To(Equal([]byte("foo")))
|
|
checkCallback(doneCb, called1)
|
|
offset, data, doneCb = s.Pop()
|
|
Expect(offset).To(Equal(protocol.ByteCount(3)))
|
|
Expect(data).To(Equal([]byte("bar")))
|
|
checkCallback(doneCb, called2)
|
|
offset, data, doneCb = s.Pop()
|
|
Expect(offset).To(Equal(protocol.ByteCount(6)))
|
|
Expect(data).To(BeNil())
|
|
Expect(doneCb).To(BeNil())
|
|
})
|
|
|
|
It("ignores empty frames", func() {
|
|
Expect(s.Push(nil, 0, nil)).To(Succeed())
|
|
_, data, doneCb := s.Pop()
|
|
Expect(data).To(BeNil())
|
|
Expect(doneCb).To(BeNil())
|
|
})
|
|
|
|
It("says if has more data", func() {
|
|
Expect(s.HasMoreData()).To(BeFalse())
|
|
Expect(s.Push([]byte("foo"), 0, nil)).To(Succeed())
|
|
Expect(s.HasMoreData()).To(BeTrue())
|
|
_, data, _ := s.Pop()
|
|
Expect(data).To(Equal([]byte("foo")))
|
|
Expect(s.HasMoreData()).To(BeFalse())
|
|
})
|
|
|
|
Context("Gap handling", func() {
|
|
It("finds the first gap", func() {
|
|
Expect(s.Push([]byte("foobar"), 10, nil)).To(Succeed())
|
|
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() {
|
|
Expect(s.Push([]byte("foobar"), 0, nil)).To(Succeed())
|
|
checkGaps([]utils.ByteInterval{
|
|
{Start: 6, End: protocol.MaxByteCount},
|
|
})
|
|
})
|
|
|
|
It("finds the two gaps", func() {
|
|
Expect(s.Push([]byte("foobar"), 10, nil)).To(Succeed())
|
|
Expect(s.Push([]byte("foobar"), 20, nil)).To(Succeed())
|
|
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() {
|
|
Expect(s.Push([]byte("foobar"), 20, nil)).To(Succeed())
|
|
Expect(s.Push([]byte("foobar"), 10, nil)).To(Succeed())
|
|
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() {
|
|
Expect(s.Push([]byte("test"), 10, nil)).To(Succeed())
|
|
Expect(s.Push([]byte("foobar"), 4, nil)).To(Succeed())
|
|
checkGaps([]utils.ByteInterval{
|
|
{Start: 0, End: 4},
|
|
{Start: 14, End: protocol.MaxByteCount},
|
|
})
|
|
})
|
|
|
|
It("deletes a gap at the beginning, when it is filled", func() {
|
|
Expect(s.Push([]byte("test"), 6, nil)).To(Succeed())
|
|
Expect(s.Push([]byte("foobar"), 0, nil)).To(Succeed())
|
|
checkGaps([]utils.ByteInterval{
|
|
{Start: 10, End: protocol.MaxByteCount},
|
|
})
|
|
})
|
|
|
|
It("deletes a gap in the middle, when it is filled", func() {
|
|
Expect(s.Push([]byte("test"), 0, nil)).To(Succeed())
|
|
Expect(s.Push([]byte("test2"), 10, nil)).To(Succeed())
|
|
Expect(s.Push([]byte("foobar"), 4, nil)).To(Succeed())
|
|
Expect(s.queue).To(HaveLen(3))
|
|
checkGaps([]utils.ByteInterval{
|
|
{Start: 15, End: protocol.MaxByteCount},
|
|
})
|
|
})
|
|
|
|
It("splits a gap into two", func() {
|
|
Expect(s.Push([]byte("test"), 100, nil)).To(Succeed())
|
|
Expect(s.Push([]byte("foobar"), 50, nil)).To(Succeed())
|
|
Expect(s.queue).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() {
|
|
var initialCb1, initialCb2, initialCb3 func()
|
|
var initialCb1Called, initialCb2Called, initialCb3Called *bool
|
|
|
|
// create gaps: 0-500, 1000-1500, 2000-2500, 3000-inf
|
|
BeforeEach(func() {
|
|
// make sure frames are not cut when we overlap a little bit
|
|
Expect(protocol.MinStreamFrameBufferSize).To(BeNumerically("<", 500/2))
|
|
initialCb1, initialCb1Called = getCallback()
|
|
initialCb2, initialCb2Called = getCallback()
|
|
initialCb3, initialCb3Called = getCallback()
|
|
Expect(s.Push(bytes.Repeat([]byte{1}, 500), 500, initialCb1)).To(Succeed())
|
|
Expect(s.Push(bytes.Repeat([]byte{2}, 500), 1500, initialCb2)).To(Succeed())
|
|
Expect(s.Push(bytes.Repeat([]byte{3}, 500), 2500, initialCb3)).To(Succeed())
|
|
checkGaps([]utils.ByteInterval{
|
|
{Start: 0, End: 500},
|
|
{Start: 1000, End: 1500},
|
|
{Start: 2000, End: 2500},
|
|
{Start: 3000, End: protocol.MaxByteCount},
|
|
})
|
|
})
|
|
|
|
It("cuts a frame with offset 0 that overlaps at the end", func() {
|
|
cb, called := getCallback()
|
|
// 0 - 505
|
|
Expect(s.Push(bytes.Repeat([]byte{9}, 505), 0, cb)).To(Succeed())
|
|
Expect(s.queue).To(HaveKey(protocol.ByteCount(0)))
|
|
Expect(s.queue[0].Data).To(Equal(bytes.Repeat([]byte{9}, 500))) // 0 to 500
|
|
checkGaps([]utils.ByteInterval{
|
|
{Start: 1000, End: 1500},
|
|
{Start: 2000, End: 2500},
|
|
{Start: 3000, End: protocol.MaxByteCount},
|
|
})
|
|
checkCallback(cb, called)
|
|
checkCallback(initialCb1, initialCb1Called)
|
|
checkCallback(initialCb2, initialCb2Called)
|
|
checkCallback(initialCb3, initialCb3Called)
|
|
})
|
|
|
|
It("cuts a frame that overlaps at the end", func() {
|
|
cb, called := getCallback()
|
|
// 100 to 600
|
|
Expect(s.Push(bytes.Repeat([]byte{9}, 500), 100, cb)).To(Succeed())
|
|
Expect(s.queue).To(HaveKey(protocol.ByteCount(100)))
|
|
Expect(s.queue[100].Data).To(Equal(bytes.Repeat([]byte{9}, 400))) // 100 to 500
|
|
checkGaps([]utils.ByteInterval{
|
|
{Start: 0, End: 100},
|
|
{Start: 1000, End: 1500},
|
|
{Start: 2000, End: 2500},
|
|
{Start: 3000, End: protocol.MaxByteCount},
|
|
})
|
|
checkCallback(cb, called)
|
|
checkCallback(initialCb1, initialCb1Called)
|
|
checkCallback(initialCb2, initialCb2Called)
|
|
checkCallback(initialCb3, initialCb3Called)
|
|
})
|
|
|
|
It("cuts a frame that completely fills a gap, but overlaps at the end", func() {
|
|
// 1000 to 1600
|
|
cb, called := getCallback()
|
|
Expect(s.Push(bytes.Repeat([]byte{9}, 600), 1000, cb)).To(Succeed())
|
|
Expect(s.queue).To(HaveKey(protocol.ByteCount(1000)))
|
|
Expect(s.queue[1000].Data).To(Equal(bytes.Repeat([]byte{9}, 500))) // 1000 to 15000
|
|
checkGaps([]utils.ByteInterval{
|
|
{Start: 0, End: 500},
|
|
{Start: 2000, End: 2500},
|
|
{Start: 3000, End: protocol.MaxByteCount},
|
|
})
|
|
checkCallback(cb, called)
|
|
checkCallback(initialCb1, initialCb1Called)
|
|
checkCallback(initialCb2, initialCb2Called)
|
|
checkCallback(initialCb3, initialCb3Called)
|
|
})
|
|
|
|
It("cuts a frame that overlaps at the beginning", func() {
|
|
cb, called := getCallback()
|
|
// 900 to 1400
|
|
Expect(s.Push(bytes.Repeat([]byte{9}, 500), 900, cb)).To(Succeed())
|
|
Expect(s.queue).ToNot(HaveKey(protocol.ByteCount(900)))
|
|
Expect(s.queue).To(HaveKey(protocol.ByteCount(1000)))
|
|
Expect(s.queue[1000].Data).To(Equal(bytes.Repeat([]byte{9}, 400))) // 1000 to 1400
|
|
checkGaps([]utils.ByteInterval{
|
|
{Start: 0, End: 500},
|
|
{Start: 1400, End: 1500},
|
|
{Start: 2000, End: 2500},
|
|
{Start: 3000, End: protocol.MaxByteCount},
|
|
})
|
|
checkCallback(cb, called)
|
|
checkCallback(initialCb1, initialCb1Called)
|
|
checkCallback(initialCb2, initialCb2Called)
|
|
checkCallback(initialCb3, initialCb3Called)
|
|
})
|
|
|
|
It("processes a frame that overlaps at the beginning and at the end, starting in a gap", func() {
|
|
cb, called := getCallback()
|
|
// 300 to 1100
|
|
Expect(s.Push(bytes.Repeat([]byte{9}, 800), 300, cb)).To(Succeed())
|
|
Expect(s.queue).To(HaveKey(protocol.ByteCount(300)))
|
|
Expect(s.queue[300].Data).To(Equal(bytes.Repeat([]byte{9}, 800))) // 300 to 1100
|
|
checkGaps([]utils.ByteInterval{
|
|
{Start: 0, End: 300},
|
|
{Start: 1100, End: 1500},
|
|
{Start: 2000, End: 2500},
|
|
{Start: 3000, End: protocol.MaxByteCount},
|
|
})
|
|
checkCallback(cb, called)
|
|
// initial1 spanned from 500 - 1000, and should have been deleted
|
|
Expect(*initialCb1Called).To(BeTrue())
|
|
checkCallback(initialCb2, initialCb2Called)
|
|
checkCallback(initialCb3, initialCb3Called)
|
|
})
|
|
|
|
It("processes a frame that overlaps at the beginning and at the end, starting in a gap, ending in data", func() {
|
|
cb, called := getCallback()
|
|
// 400 to 1600
|
|
Expect(s.Push(bytes.Repeat([]byte{9}, 1200), 400, cb)).To(Succeed())
|
|
Expect(s.queue).To(HaveKey(protocol.ByteCount(400)))
|
|
Expect(s.queue).To(HaveKey(protocol.ByteCount(1500)))
|
|
Expect(s.queue[400].Data).To(Equal(bytes.Repeat([]byte{9}, 1100))) // 400 to 1500
|
|
checkGaps([]utils.ByteInterval{
|
|
{Start: 0, End: 400},
|
|
{Start: 2000, End: 2500},
|
|
{Start: 3000, End: protocol.MaxByteCount},
|
|
})
|
|
checkCallback(cb, called)
|
|
// initial1 spans from 500 - 1000, and should have been deleted
|
|
Expect(*initialCb1Called).To(BeTrue())
|
|
checkCallback(initialCb2, initialCb2Called)
|
|
checkCallback(initialCb3, initialCb3Called)
|
|
})
|
|
|
|
It("processes a frame that overlaps at the beginning and at the end, starting in a gap, ending in data", func() {
|
|
cb, called := getCallback()
|
|
// 500 to 2100
|
|
Expect(s.Push(bytes.Repeat([]byte{9}, 1600), 500, cb)).To(Succeed())
|
|
Expect(s.queue).To(HaveKey(protocol.ByteCount(500)))
|
|
Expect(s.queue[500].Data).To(Equal(bytes.Repeat([]byte{9}, 1600))) // 500 to 2100
|
|
Expect(s.queue).ToNot(HaveKey(protocol.ByteCount(1000)))
|
|
Expect(s.queue).ToNot(HaveKey(protocol.ByteCount(1500)))
|
|
checkGaps([]utils.ByteInterval{
|
|
{Start: 0, End: 500},
|
|
{Start: 2100, End: 2500},
|
|
{Start: 3000, End: protocol.MaxByteCount},
|
|
})
|
|
checkCallback(cb, called)
|
|
// initial1 spans from 500 - 1000, and should have been deleted
|
|
Expect(*initialCb1Called).To(BeTrue())
|
|
// initial2 spans from 1500 - 2000, and should have been deleted
|
|
Expect(*initialCb2Called).To(BeTrue())
|
|
checkCallback(initialCb3, initialCb3Called)
|
|
})
|
|
|
|
It("processes a frame that closes multiple gaps, beginning in a gap", func() {
|
|
cb, called := getCallback()
|
|
// 400 to 3100
|
|
Expect(s.Push(bytes.Repeat([]byte{9}, 2700), 400, cb)).To(Succeed())
|
|
Expect(s.queue).ToNot(HaveKey(protocol.ByteCount(500)))
|
|
Expect(s.queue).ToNot(HaveKey(protocol.ByteCount(1500)))
|
|
Expect(s.queue).ToNot(HaveKey(protocol.ByteCount(2500)))
|
|
Expect(s.queue).To(HaveKey(protocol.ByteCount(400)))
|
|
Expect(s.queue[400].Data).To(Equal(bytes.Repeat([]byte{9}, 2700))) // 400 to 3100
|
|
checkGaps([]utils.ByteInterval{
|
|
{Start: 0, End: 400},
|
|
{Start: 3100, End: protocol.MaxByteCount},
|
|
})
|
|
checkCallback(cb, called)
|
|
// initial1 spans from 500 - 1000, and should have been deleted
|
|
Expect(*initialCb1Called).To(BeTrue())
|
|
// initial2 spans from 1500 - 2000, and should have been deleted
|
|
Expect(*initialCb2Called).To(BeTrue())
|
|
// initial3 spans from 2500 - 3100, and should have been deleted
|
|
Expect(*initialCb3Called).To(BeTrue())
|
|
})
|
|
|
|
It("processes a frame that closes multiple gaps, beginning at the end of a gap", func() {
|
|
cb, called := getCallback()
|
|
// 500 to 2600
|
|
Expect(s.Push(bytes.Repeat([]byte{9}, 2100), 500, cb)).To(Succeed())
|
|
Expect(s.queue).To(HaveKey(protocol.ByteCount(500)))
|
|
Expect(s.queue).ToNot(HaveKey(protocol.ByteCount(1000)))
|
|
Expect(s.queue).ToNot(HaveKey(protocol.ByteCount(1500)))
|
|
Expect(s.queue).To(HaveKey(protocol.ByteCount(2500)))
|
|
Expect(s.queue[500].Data).To(Equal(bytes.Repeat([]byte{9}, 2000))) // 500 to 2500
|
|
checkGaps([]utils.ByteInterval{
|
|
{Start: 0, End: 500},
|
|
{Start: 3000, End: protocol.MaxByteCount},
|
|
})
|
|
checkCallback(cb, called)
|
|
// initial1 spans from 500 - 1000, and should have been deleted
|
|
Expect(*initialCb1Called).To(BeTrue())
|
|
// initial2 spans from 1500 - 2000, and should have been deleted
|
|
Expect(*initialCb2Called).To(BeTrue())
|
|
checkCallback(initialCb3, initialCb3Called)
|
|
})
|
|
|
|
It("processes a frame that covers multiple gaps and ends at the end of a gap", func() {
|
|
cb, called := getCallback()
|
|
// 100 to 1500
|
|
Expect(s.Push(bytes.Repeat([]byte{9}, 1400), 100, cb)).To(Succeed())
|
|
Expect(s.queue).To(HaveKey(protocol.ByteCount(100)))
|
|
Expect(s.queue).To(HaveKey(protocol.ByteCount(1500)))
|
|
Expect(s.queue).ToNot(HaveKey(protocol.ByteCount(500)))
|
|
Expect(s.queue[100].Data).To(Equal(bytes.Repeat([]byte{9}, 1400))) // 100 to 1500
|
|
checkGaps([]utils.ByteInterval{
|
|
{Start: 0, End: 100},
|
|
{Start: 2000, End: 2500},
|
|
{Start: 3000, End: protocol.MaxByteCount},
|
|
})
|
|
checkCallback(cb, called)
|
|
// initial1 spans from 500 - 1000, and should have been deleted
|
|
Expect(*initialCb1Called).To(BeTrue())
|
|
checkCallback(initialCb2, initialCb2Called)
|
|
checkCallback(initialCb3, initialCb3Called)
|
|
})
|
|
|
|
It("processes a frame that closes all gaps (except for the last one)", func() {
|
|
cb, called := getCallback()
|
|
// 0 to 3100
|
|
Expect(s.Push(bytes.Repeat([]byte{9}, 3100), 0, cb)).To(Succeed())
|
|
Expect(s.queue).To(HaveLen(1))
|
|
Expect(s.queue).To(HaveKey(protocol.ByteCount(0)))
|
|
Expect(s.queue[0].Data).To(Equal(bytes.Repeat([]byte{9}, 3100))) // 0 to 3100
|
|
checkGaps([]utils.ByteInterval{
|
|
{Start: 3100, End: protocol.MaxByteCount},
|
|
})
|
|
checkCallback(cb, called)
|
|
// initial1 spans from 500 - 1000, and should have been deleted
|
|
Expect(*initialCb1Called).To(BeTrue())
|
|
Expect(*initialCb2Called).To(BeTrue())
|
|
Expect(*initialCb3Called).To(BeTrue())
|
|
})
|
|
})
|
|
|
|
Context("duplicate data", func() {
|
|
var initialCb1, initialCb2 func()
|
|
var initialCb1Called, initialCb2Called *bool
|
|
|
|
BeforeEach(func() {
|
|
// make sure frames are not cut when we overlap a little bit
|
|
Expect(protocol.MinStreamFrameBufferSize).To(BeNumerically("<", 500/2))
|
|
initialCb1, initialCb1Called = getCallback()
|
|
initialCb2, initialCb2Called = getCallback()
|
|
// create gaps: 500 - 1000, 1500 - inf
|
|
Expect(s.Push(bytes.Repeat([]byte{1}, 500), 0, initialCb1)).To(Succeed())
|
|
Expect(s.Push(bytes.Repeat([]byte{2}, 500), 1000, initialCb1)).To(Succeed())
|
|
checkGaps([]utils.ByteInterval{
|
|
{Start: 500, End: 1000},
|
|
{Start: 1500, End: protocol.MaxByteCount},
|
|
})
|
|
})
|
|
|
|
AfterEach(func() {
|
|
// check that the gaps were not modified
|
|
checkGaps([]utils.ByteInterval{
|
|
{Start: 500, End: 1000},
|
|
{Start: 1500, End: protocol.MaxByteCount},
|
|
})
|
|
})
|
|
|
|
It("does not modify data when receiving a duplicate", func() {
|
|
cb, called := getCallback()
|
|
// 0 to 500
|
|
Expect(s.Push(bytes.Repeat([]byte{9}, 500), 0, cb)).To(Succeed())
|
|
Expect(s.queue).To(HaveKey(protocol.ByteCount(0)))
|
|
Expect(s.queue[0].Data).ToNot(Equal(bytes.Repeat([]byte{9}, 500)))
|
|
Expect(*called).To(BeTrue())
|
|
checkCallback(initialCb1, initialCb1Called)
|
|
checkCallback(initialCb2, initialCb2Called)
|
|
})
|
|
|
|
It("detects a duplicate frame that is smaller than the original, starting at the beginning", func() {
|
|
cb, called := getCallback()
|
|
// 1000 to 1200
|
|
Expect(s.Push(bytes.Repeat([]byte{9}, 200), 1000, cb)).To(Succeed())
|
|
Expect(s.queue).To(HaveKey(protocol.ByteCount(1000)))
|
|
Expect(s.queue[1000].Data).ToNot(Equal(bytes.Repeat([]byte{9}, 200)))
|
|
Expect(*called).To(BeTrue())
|
|
checkCallback(initialCb1, initialCb1Called)
|
|
checkCallback(initialCb2, initialCb2Called)
|
|
})
|
|
|
|
It("detects a duplicate frame that is smaller than the original, somewhere in the middle", func() {
|
|
cb, called := getCallback()
|
|
// 100 to 400
|
|
Expect(s.Push(bytes.Repeat([]byte{9}, 300), 100, cb)).To(Succeed())
|
|
Expect(s.queue).ToNot(HaveKey(protocol.ByteCount(100)))
|
|
Expect(s.queue[0].Data).To(Equal(bytes.Repeat([]byte{1}, 500)))
|
|
Expect(*called).To(BeTrue())
|
|
checkCallback(initialCb1, initialCb1Called)
|
|
checkCallback(initialCb2, initialCb2Called)
|
|
})
|
|
|
|
It("detects a duplicate frame that is smaller than the original, somewhere in the middle in the last block", func() {
|
|
cb, called := getCallback()
|
|
// 1100 to 1400
|
|
Expect(s.Push(bytes.Repeat([]byte{9}, 300), 1100, cb)).To(Succeed())
|
|
Expect(s.queue).ToNot(HaveKey(protocol.ByteCount(1100)))
|
|
Expect(s.queue[1000].Data).To(Equal(bytes.Repeat([]byte{2}, 500)))
|
|
Expect(*called).To(BeTrue())
|
|
checkCallback(initialCb1, initialCb1Called)
|
|
checkCallback(initialCb2, initialCb2Called)
|
|
})
|
|
|
|
It("detects a duplicate frame that is smaller than the original, somewhere in the middle in the last block", func() {
|
|
cb, called := getCallback()
|
|
// 1100 to 1500
|
|
Expect(s.Push(bytes.Repeat([]byte{9}, 400), 1100, cb)).To(Succeed())
|
|
Expect(s.queue).ToNot(HaveKey(protocol.ByteCount(1100)))
|
|
Expect(s.queue[1000].Data).To(Equal(bytes.Repeat([]byte{2}, 500)))
|
|
Expect(*called).To(BeTrue())
|
|
checkCallback(initialCb1, initialCb1Called)
|
|
checkCallback(initialCb2, initialCb2Called)
|
|
})
|
|
|
|
It("detects a duplicate frame that is smaller than the original, with aligned end", func() {
|
|
cb, called := getCallback()
|
|
// 300 to 500
|
|
Expect(s.Push(bytes.Repeat([]byte{9}, 200), 300, cb)).To(Succeed())
|
|
Expect(s.queue).ToNot(HaveKey(protocol.ByteCount(300)))
|
|
Expect(s.queue[0].Data).To(Equal(bytes.Repeat([]byte{1}, 500)))
|
|
Expect(*called).To(BeTrue())
|
|
checkCallback(initialCb1, initialCb1Called)
|
|
checkCallback(initialCb2, initialCb2Called)
|
|
})
|
|
})
|
|
|
|
Context("cutting short frames", func() {
|
|
var initialCb1, initialCb2 func()
|
|
var initialCb1Called, initialCb2Called *bool
|
|
|
|
// create gaps: 0-5, 10-15, 2000-inf
|
|
BeforeEach(func() {
|
|
// make sure frames are not cut when we overlap a little bit
|
|
Expect(protocol.MinStreamFrameBufferSize).To(BeNumerically(">", 10))
|
|
initialCb1, initialCb1Called = getCallback()
|
|
initialCb2, initialCb2Called = getCallback()
|
|
Expect(s.Push(bytes.Repeat([]byte{1}, 5), 5, initialCb1)).To(Succeed())
|
|
Expect(s.Push(bytes.Repeat([]byte{2}, 5), 15, initialCb2)).To(Succeed())
|
|
checkGaps([]utils.ByteInterval{
|
|
{Start: 0, End: 5},
|
|
{Start: 10, End: 15},
|
|
{Start: 20, End: protocol.MaxByteCount},
|
|
})
|
|
})
|
|
|
|
It("cuts a frame that overlaps with received data at the beginning", func() {
|
|
cb, called := getCallback()
|
|
// 9 to 12
|
|
Expect(s.Push(bytes.Repeat([]byte{9}, 3), 9, cb)).To(Succeed())
|
|
Expect(s.queue).ToNot(HaveKey(protocol.ByteCount(9)))
|
|
Expect(s.queue).To(HaveKey(protocol.ByteCount(10)))
|
|
Expect(s.queue[10].Data).To(Equal(bytes.Repeat([]byte{9}, 2))) // 10 to 12
|
|
Expect(s.queue[10].Data).To(HaveCap(2))
|
|
checkGaps([]utils.ByteInterval{
|
|
{Start: 0, End: 5},
|
|
{Start: 12, End: 15},
|
|
{Start: 20, End: protocol.MaxByteCount},
|
|
})
|
|
Expect(*called).To(BeTrue())
|
|
checkCallback(initialCb1, initialCb1Called)
|
|
checkCallback(initialCb2, initialCb2Called)
|
|
})
|
|
|
|
It("cuts a frame that overlaps with received data at the end", func() {
|
|
cb, called := getCallback()
|
|
// 12 to 19
|
|
Expect(s.Push(bytes.Repeat([]byte{9}, 7), 12, cb)).To(Succeed())
|
|
Expect(s.queue).To(HaveKey(protocol.ByteCount(12)))
|
|
Expect(s.queue[12].Data).To(Equal(bytes.Repeat([]byte{9}, 3))) // 12 to 15
|
|
Expect(s.queue[12].Data).To(HaveCap(3))
|
|
checkGaps([]utils.ByteInterval{
|
|
{Start: 0, End: 5},
|
|
{Start: 10, End: 12},
|
|
{Start: 20, End: protocol.MaxByteCount},
|
|
})
|
|
Expect(*called).To(BeTrue())
|
|
checkCallback(initialCb1, initialCb1Called)
|
|
checkCallback(initialCb2, initialCb2Called)
|
|
})
|
|
})
|
|
|
|
Context("DoS protection", func() {
|
|
It("errors when too many gaps are created", func() {
|
|
for i := 0; i < protocol.MaxStreamFrameSorterGaps; i++ {
|
|
Expect(s.Push([]byte("foobar"), protocol.ByteCount(i*7), nil)).To(Succeed())
|
|
}
|
|
Expect(s.gaps.Len()).To(Equal(protocol.MaxStreamFrameSorterGaps))
|
|
err := s.Push([]byte("foobar"), protocol.ByteCount(protocol.MaxStreamFrameSorterGaps*7)+100, nil)
|
|
Expect(err).To(MatchError("Too many gaps in received data"))
|
|
})
|
|
})
|
|
})
|
|
})
|
|
})
|