forked from quic-go/quic-go
Merge pull request #454 from lucas-clemente/streamframesorter
accept overlapping stream data
This commit is contained in:
@@ -5,7 +5,6 @@ import (
|
||||
|
||||
"github.com/lucas-clemente/quic-go/frames"
|
||||
"github.com/lucas-clemente/quic-go/protocol"
|
||||
"github.com/lucas-clemente/quic-go/qerr"
|
||||
"github.com/lucas-clemente/quic-go/utils"
|
||||
)
|
||||
|
||||
@@ -17,7 +16,7 @@ type streamFrameSorter struct {
|
||||
|
||||
var (
|
||||
errTooManyGapsInReceivedStreamData = errors.New("Too many gaps in received StreamFrame data")
|
||||
errDuplicateStreamData = errors.New("Overlapping Stream Data")
|
||||
errDuplicateStreamData = errors.New("Duplicate Stream Data")
|
||||
errEmptyStreamData = errors.New("Stream Data empty")
|
||||
)
|
||||
|
||||
@@ -31,15 +30,7 @@ func newStreamFrameSorter() *streamFrameSorter {
|
||||
}
|
||||
|
||||
func (s *streamFrameSorter) Push(frame *frames.StreamFrame) error {
|
||||
_, ok := s.queuedFrames[frame.Offset]
|
||||
if ok {
|
||||
return errDuplicateStreamData
|
||||
}
|
||||
|
||||
start := frame.Offset
|
||||
end := frame.Offset + frame.DataLen()
|
||||
|
||||
if start == end {
|
||||
if frame.DataLen() == 0 {
|
||||
if frame.FinBit {
|
||||
s.queuedFrames[frame.Offset] = frame
|
||||
return nil
|
||||
@@ -47,56 +38,108 @@ func (s *streamFrameSorter) Push(frame *frames.StreamFrame) error {
|
||||
return errEmptyStreamData
|
||||
}
|
||||
|
||||
var foundInGap bool
|
||||
|
||||
for gap := s.gaps.Front(); gap != nil; gap = gap.Next() {
|
||||
// the complete frame lies before or after the gap
|
||||
if end <= gap.Value.Start || start > gap.Value.End {
|
||||
continue
|
||||
var wasCut bool
|
||||
if oldFrame, ok := s.queuedFrames[frame.Offset]; ok {
|
||||
if frame.DataLen() <= oldFrame.DataLen() {
|
||||
return errDuplicateStreamData
|
||||
}
|
||||
frame.Data = frame.Data[oldFrame.DataLen():]
|
||||
frame.Offset += oldFrame.DataLen()
|
||||
wasCut = true
|
||||
}
|
||||
|
||||
if start < gap.Value.Start {
|
||||
return qerr.Error(qerr.OverlappingStreamData, "start of gap in stream chunk")
|
||||
}
|
||||
start := frame.Offset
|
||||
end := frame.Offset + frame.DataLen()
|
||||
|
||||
if start < gap.Value.End && end > gap.Value.End {
|
||||
return qerr.Error(qerr.OverlappingStreamData, "end of gap in stream chunk")
|
||||
}
|
||||
// the frame is a duplicate. Ignore it
|
||||
if end <= s.gaps.Front().Value.Start {
|
||||
return errDuplicateStreamData
|
||||
}
|
||||
|
||||
foundInGap = true
|
||||
|
||||
if start == gap.Value.Start {
|
||||
if end == gap.Value.End {
|
||||
s.gaps.Remove(gap)
|
||||
break
|
||||
}
|
||||
if end < gap.Value.End {
|
||||
gap.Value.Start = end
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if end == gap.Value.End {
|
||||
gap.Value.End = start
|
||||
break
|
||||
}
|
||||
|
||||
if end < gap.Value.End {
|
||||
intv := utils.ByteInterval{Start: end, End: gap.Value.End}
|
||||
s.gaps.InsertAfter(intv, gap)
|
||||
gap.Value.End = start
|
||||
// skip all gaps that are before this stream frame
|
||||
var gap *utils.ByteIntervalElement
|
||||
for gap = s.gaps.Front(); gap != nil; gap = gap.Next() {
|
||||
if end > gap.Value.Start && start <= gap.Value.End {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !foundInGap {
|
||||
return errDuplicateStreamData
|
||||
if gap == nil {
|
||||
return errors.New("StreamFrameSorter BUG: no gap found")
|
||||
}
|
||||
|
||||
if start < gap.Value.Start {
|
||||
add := gap.Value.Start - start
|
||||
frame.Offset += add
|
||||
start += add
|
||||
frame.Data = frame.Data[add:]
|
||||
wasCut = true
|
||||
}
|
||||
|
||||
// find the highest gaps whose Start lies before the end of the frame
|
||||
endGap := gap
|
||||
for end >= endGap.Value.End {
|
||||
nextEndGap := endGap.Next()
|
||||
if nextEndGap == nil {
|
||||
return errors.New("StreamFrameSorter BUG: no end gap found")
|
||||
}
|
||||
if endGap != gap {
|
||||
s.gaps.Remove(endGap)
|
||||
}
|
||||
if end <= nextEndGap.Value.Start {
|
||||
break
|
||||
}
|
||||
// delete queued frames completely covered by the current frame
|
||||
delete(s.queuedFrames, endGap.Value.End)
|
||||
endGap = nextEndGap
|
||||
}
|
||||
|
||||
if end > endGap.Value.End {
|
||||
cutLen := end - endGap.Value.End
|
||||
len := frame.DataLen() - cutLen
|
||||
end -= cutLen
|
||||
frame.Data = frame.Data[:len]
|
||||
wasCut = true
|
||||
}
|
||||
|
||||
if start == gap.Value.Start {
|
||||
if end >= gap.Value.End {
|
||||
// the frame completely fills this gap
|
||||
// delete the gap
|
||||
s.gaps.Remove(gap)
|
||||
}
|
||||
if end < endGap.Value.End {
|
||||
// the frame covers the beginning of the gap
|
||||
// adjust the Start value to shrink the gap
|
||||
endGap.Value.Start = end
|
||||
}
|
||||
} else if end == endGap.Value.End {
|
||||
// the frame covers the end of the gap
|
||||
// adjust the End value to shrink the gap
|
||||
gap.Value.End = start
|
||||
} else {
|
||||
if gap == endGap {
|
||||
// the frame lies within the current gap, splitting it into two
|
||||
// insert a new gap and adjust the current one
|
||||
intv := utils.ByteInterval{Start: end, End: gap.Value.End}
|
||||
s.gaps.InsertAfter(intv, gap)
|
||||
gap.Value.End = start
|
||||
} else {
|
||||
gap.Value.End = start
|
||||
endGap.Value.Start = end
|
||||
}
|
||||
}
|
||||
|
||||
if s.gaps.Len() > protocol.MaxStreamFrameSorterGaps {
|
||||
return errTooManyGapsInReceivedStreamData
|
||||
}
|
||||
|
||||
if wasCut {
|
||||
data := make([]byte, frame.DataLen())
|
||||
copy(data, frame.Data)
|
||||
frame.Data = data
|
||||
}
|
||||
|
||||
s.queuedFrames[frame.Offset] = frame
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package quic
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
||||
"github.com/lucas-clemente/quic-go/frames"
|
||||
"github.com/lucas-clemente/quic-go/protocol"
|
||||
"github.com/lucas-clemente/quic-go/utils"
|
||||
@@ -8,18 +10,18 @@ import (
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
func compareGapValues(gapList *utils.ByteIntervalList, expectedGaps []utils.ByteInterval) {
|
||||
Expect(gapList.Len()).To(Equal(len(expectedGaps)))
|
||||
var i int
|
||||
for gap := gapList.Front(); gap != nil; gap = gap.Next() {
|
||||
Expect(gap.Value).To(Equal(expectedGaps[i]))
|
||||
i++
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
})
|
||||
@@ -102,8 +104,10 @@ var _ = Describe("StreamFrame sorter", func() {
|
||||
}
|
||||
err := s.Push(f)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(s.gaps.Len()).To(Equal(2))
|
||||
Expect(s.gaps.Front().Value).To(Equal(utils.ByteInterval{Start: 0, End: 10}))
|
||||
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() {
|
||||
@@ -113,8 +117,9 @@ var _ = Describe("StreamFrame sorter", func() {
|
||||
}
|
||||
err := s.Push(f)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(s.gaps.Len()).To(Equal(1))
|
||||
Expect(s.gaps.Front().Value).To(Equal(utils.ByteInterval{Start: 6, End: protocol.MaxByteCount}))
|
||||
checkGaps([]utils.ByteInterval{
|
||||
{Start: 6, End: protocol.MaxByteCount},
|
||||
})
|
||||
})
|
||||
|
||||
It("finds the two gaps", func() {
|
||||
@@ -130,12 +135,11 @@ var _ = Describe("StreamFrame sorter", func() {
|
||||
}
|
||||
err = s.Push(f2)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(s.gaps.Len()).To(Equal(3))
|
||||
el := s.gaps.Front() // first gap
|
||||
Expect(el.Value).To(Equal(utils.ByteInterval{Start: 0, End: 10}))
|
||||
el = el.Next() // second gap
|
||||
Expect(el.Value).To(Equal(utils.ByteInterval{Start: 16, End: 20}))
|
||||
Expect(s.gaps.Back().Value.Start).To(Equal(protocol.ByteCount(26)))
|
||||
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() {
|
||||
@@ -151,12 +155,11 @@ var _ = Describe("StreamFrame sorter", func() {
|
||||
}
|
||||
err = s.Push(f2)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(s.gaps.Len()).To(Equal(3))
|
||||
el := s.gaps.Front() // first gap
|
||||
Expect(el.Value).To(Equal(utils.ByteInterval{Start: 0, End: 10}))
|
||||
el = el.Next() // second gap
|
||||
Expect(el.Value).To(Equal(utils.ByteInterval{Start: 16, End: 20}))
|
||||
Expect(s.gaps.Back().Value).To(Equal(utils.ByteInterval{Start: 26, End: protocol.MaxByteCount}))
|
||||
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() {
|
||||
@@ -172,9 +175,10 @@ var _ = Describe("StreamFrame sorter", func() {
|
||||
}
|
||||
err = s.Push(f2)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(s.gaps.Len()).To(Equal(2))
|
||||
Expect(s.gaps.Front().Value).To(Equal(utils.ByteInterval{Start: 0, End: 4}))
|
||||
Expect(s.gaps.Back().Value).To(Equal(utils.ByteInterval{Start: 14, End: protocol.MaxByteCount}))
|
||||
checkGaps([]utils.ByteInterval{
|
||||
{Start: 0, End: 4},
|
||||
{Start: 14, End: protocol.MaxByteCount},
|
||||
})
|
||||
})
|
||||
|
||||
It("deletes a gap at the beginning, when it is filled", func() {
|
||||
@@ -190,8 +194,9 @@ var _ = Describe("StreamFrame sorter", func() {
|
||||
}
|
||||
err = s.Push(f2)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(s.gaps.Len()).To(Equal(1))
|
||||
Expect(s.gaps.Front().Value).To(Equal(utils.ByteInterval{Start: 10, End: protocol.MaxByteCount}))
|
||||
checkGaps([]utils.ByteInterval{
|
||||
{Start: 10, End: protocol.MaxByteCount},
|
||||
})
|
||||
})
|
||||
|
||||
It("deletes a gap in the middle, when it is filled", func() {
|
||||
@@ -213,9 +218,10 @@ var _ = Describe("StreamFrame sorter", func() {
|
||||
}
|
||||
err = s.Push(f3)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(s.gaps.Len()).To(Equal(1))
|
||||
Expect(s.gaps.Front().Value).To(Equal(utils.ByteInterval{Start: 15, End: protocol.MaxByteCount}))
|
||||
Expect(s.queuedFrames).To(HaveLen(3))
|
||||
checkGaps([]utils.ByteInterval{
|
||||
{Start: 15, End: protocol.MaxByteCount},
|
||||
})
|
||||
})
|
||||
|
||||
It("splits a gap into two", func() {
|
||||
@@ -231,167 +237,321 @@ var _ = Describe("StreamFrame sorter", func() {
|
||||
}
|
||||
err = s.Push(f2)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(s.gaps.Len()).To(Equal(3))
|
||||
el := s.gaps.Front() // first gap
|
||||
Expect(el.Value).To(Equal(utils.ByteInterval{Start: 0, End: 50}))
|
||||
el = el.Next() // second gap
|
||||
Expect(el.Value).To(Equal(utils.ByteInterval{Start: 56, End: 100}))
|
||||
Expect(s.gaps.Back().Value).To(Equal(utils.ByteInterval{Start: 104, End: protocol.MaxByteCount}))
|
||||
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() {
|
||||
var expectedGaps []utils.ByteInterval
|
||||
// create gaps: 0-5, 10-15, 20-25, 30-inf
|
||||
BeforeEach(func() {
|
||||
// create gaps: 0-5, 10-15, 15-20, 30-inf
|
||||
expectedGaps = expectedGaps[:0]
|
||||
expectedGaps = append(expectedGaps, utils.ByteInterval{Start: 0, End: 5})
|
||||
err := s.Push(&frames.StreamFrame{Offset: 5, Data: []byte("12345")})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
expectedGaps = append(expectedGaps, utils.ByteInterval{Start: 10, End: 15})
|
||||
err = s.Push(&frames.StreamFrame{Offset: 15, Data: []byte("12345")})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
expectedGaps = append(expectedGaps, utils.ByteInterval{Start: 20, End: 25})
|
||||
err = s.Push(&frames.StreamFrame{Offset: 25, Data: []byte("12345")})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
expectedGaps = append(expectedGaps, utils.ByteInterval{Start: 30, End: protocol.MaxByteCount})
|
||||
checkGaps([]utils.ByteInterval{
|
||||
{Start: 0, End: 5},
|
||||
{Start: 10, End: 15},
|
||||
{Start: 20, End: 25},
|
||||
{Start: 30, End: protocol.MaxByteCount},
|
||||
})
|
||||
})
|
||||
|
||||
It("rejects a frame with offset 0 that overlaps at the end", func() {
|
||||
It("cuts a frame with offset 0 that overlaps at the end", func() {
|
||||
f := &frames.StreamFrame{
|
||||
Offset: 0,
|
||||
Data: []byte("foobar"),
|
||||
}
|
||||
err := s.Push(f)
|
||||
Expect(err).To(MatchError("OverlappingStreamData: end of gap in stream chunk"))
|
||||
Expect(s.queuedFrames).ToNot(HaveKey(protocol.ByteCount(0)))
|
||||
compareGapValues(s.gaps, expectedGaps)
|
||||
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("rejects a frame that overlaps at the end", func() {
|
||||
// 4 to 6
|
||||
It("cuts a frame that overlaps at the end", func() {
|
||||
// 4 to 7
|
||||
f := &frames.StreamFrame{
|
||||
Offset: 4,
|
||||
Data: []byte("12"),
|
||||
Data: []byte("foo"),
|
||||
}
|
||||
err := s.Push(f)
|
||||
Expect(err).To(MatchError("OverlappingStreamData: end of gap in stream chunk"))
|
||||
Expect(s.queuedFrames).ToNot(HaveKey(protocol.ByteCount(4)))
|
||||
compareGapValues(s.gaps, expectedGaps)
|
||||
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("rejects a frame that completely fills a gap, but overlaps at the end", func() {
|
||||
It("cuts a frame that completely fills a gap, but overlaps at the end", func() {
|
||||
// 10 to 16
|
||||
f := &frames.StreamFrame{
|
||||
Offset: 10,
|
||||
Data: []byte("foobar"),
|
||||
}
|
||||
err := s.Push(f)
|
||||
Expect(err).To(MatchError("OverlappingStreamData: end of gap in stream chunk"))
|
||||
Expect(s.queuedFrames).ToNot(HaveKey(protocol.ByteCount(10)))
|
||||
compareGapValues(s.gaps, expectedGaps)
|
||||
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("rejects a frame that overlaps at the beginning", func() {
|
||||
It("cuts a frame that overlaps at the beginning", func() {
|
||||
// 8 to 14
|
||||
f := &frames.StreamFrame{
|
||||
Offset: 8,
|
||||
Data: []byte("foobar"),
|
||||
}
|
||||
err := s.Push(f)
|
||||
Expect(err).To(MatchError("OverlappingStreamData: start of gap in stream chunk"))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(s.queuedFrames).ToNot(HaveKey(protocol.ByteCount(8)))
|
||||
compareGapValues(s.gaps, expectedGaps)
|
||||
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("rejects a frame that overlaps at the beginning and at the end, starting in a gap", func() {
|
||||
// 2 to 11
|
||||
It("processes a frame that overlaps at the beginning and at the end, starting in a gap", func() {
|
||||
// 2 to 12
|
||||
f := &frames.StreamFrame{
|
||||
Offset: 2,
|
||||
Data: []byte("123456789"),
|
||||
Data: []byte("1234567890"),
|
||||
}
|
||||
err := s.Push(f)
|
||||
Expect(err).To(MatchError("OverlappingStreamData: end of gap in stream chunk"))
|
||||
Expect(s.queuedFrames).ToNot(HaveKey(protocol.ByteCount(2)))
|
||||
compareGapValues(s.gaps, expectedGaps)
|
||||
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("rejects a frame that overlaps at the beginning and at the end, starting in data already received", func() {
|
||||
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 := &frames.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 := &frames.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 := &frames.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 := &frames.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 := &frames.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 := &frames.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 := &frames.StreamFrame{
|
||||
Offset: 8,
|
||||
Data: []byte("123456789"),
|
||||
}
|
||||
err := s.Push(f)
|
||||
Expect(err).To(MatchError("OverlappingStreamData: start of gap in stream chunk"))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(s.queuedFrames).ToNot(HaveKey(protocol.ByteCount(8)))
|
||||
compareGapValues(s.gaps, expectedGaps)
|
||||
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("rejects a frame that completely covers two gaps", func() {
|
||||
It("cuts a frame that completely covers two gaps", func() {
|
||||
// 10 to 20
|
||||
f := &frames.StreamFrame{
|
||||
Offset: 10,
|
||||
Data: []byte("1234567890"),
|
||||
}
|
||||
err := s.Push(f)
|
||||
Expect(err).To(MatchError("OverlappingStreamData: end of gap in stream chunk"))
|
||||
Expect(s.queuedFrames).ToNot(HaveKey(protocol.ByteCount(10)))
|
||||
compareGapValues(s.gaps, expectedGaps)
|
||||
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 detection", func() {
|
||||
var expectedGaps []utils.ByteInterval
|
||||
Context("duplicate data", func() {
|
||||
expectedGaps := []utils.ByteInterval{
|
||||
{Start: 5, End: 10},
|
||||
{Start: 15, End: protocol.MaxByteCount},
|
||||
}
|
||||
|
||||
BeforeEach(func() {
|
||||
// create gaps: 5-10, 15-20, 25-inf
|
||||
expectedGaps = expectedGaps[:0]
|
||||
expectedGaps = append(expectedGaps, utils.ByteInterval{Start: 5, End: 10})
|
||||
err := s.Push(&frames.StreamFrame{Offset: 0, Data: []byte("12345")})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
expectedGaps = append(expectedGaps, utils.ByteInterval{Start: 15, End: protocol.MaxByteCount})
|
||||
err = s.Push(&frames.StreamFrame{Offset: 10, Data: []byte("12345")})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
checkGaps(expectedGaps)
|
||||
})
|
||||
|
||||
It("detects a complete duplicate frame", func() {
|
||||
err := s.Push(&frames.StreamFrame{Offset: 0, Data: []byte("12345")})
|
||||
Expect(err).To(MatchError(errDuplicateStreamData))
|
||||
compareGapValues(s.gaps, 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(&frames.StreamFrame{Offset: 0, Data: []byte("67890")})
|
||||
err := s.Push(&frames.StreamFrame{Offset: 0, Data: []byte("fffff")})
|
||||
Expect(err).To(MatchError(errDuplicateStreamData))
|
||||
Expect(s.queuedFrames[0].Data).To(Equal([]byte("12345")))
|
||||
compareGapValues(s.gaps, expectedGaps)
|
||||
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(&frames.StreamFrame{Offset: 10, Data: []byte("12")})
|
||||
Expect(err).To(MatchError(errDuplicateStreamData))
|
||||
Expect(s.queuedFrames[10].DataLen()).To(Equal(protocol.ByteCount(5)))
|
||||
compareGapValues(s.gaps, expectedGaps)
|
||||
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(&frames.StreamFrame{Offset: 1, Data: []byte("123")})
|
||||
Expect(err).To(MatchError(errDuplicateStreamData))
|
||||
Expect(s.queuedFrames[0].DataLen()).To(Equal(protocol.ByteCount(5)))
|
||||
Expect(s.queuedFrames[0].Data).To(HaveLen(5))
|
||||
Expect(s.queuedFrames).ToNot(HaveKey(protocol.ByteCount(1)))
|
||||
compareGapValues(s.gaps, expectedGaps)
|
||||
})
|
||||
|
||||
It("detects a duplicate frame that is smaller than the original, with aligned end", func() {
|
||||
// 3 to 5
|
||||
err := s.Push(&frames.StreamFrame{Offset: 3, Data: []byte("12")})
|
||||
Expect(err).To(MatchError(errDuplicateStreamData))
|
||||
Expect(s.queuedFrames[0].DataLen()).To(Equal(protocol.ByteCount(5)))
|
||||
Expect(s.queuedFrames).ToNot(HaveKey(protocol.ByteCount(8)))
|
||||
compareGapValues(s.gaps, expectedGaps)
|
||||
Expect(s.queuedFrames[0].Data).To(HaveLen(5))
|
||||
Expect(s.queuedFrames).ToNot(HaveKey(protocol.ByteCount(3)))
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -281,19 +281,23 @@ var _ = Describe("Stream", func() {
|
||||
Expect(b).To(Equal([]byte{0xDE, 0xAD, 0xBE, 0xEF}))
|
||||
})
|
||||
|
||||
It("rejects a StreamFrames with an overlapping data range", func() {
|
||||
It("doesn't rejects a StreamFrames with an overlapping data range", func() {
|
||||
frame1 := frames.StreamFrame{
|
||||
Offset: 0,
|
||||
Data: []byte("ab"),
|
||||
Data: []byte("foob"),
|
||||
}
|
||||
frame2 := frames.StreamFrame{
|
||||
Offset: 1,
|
||||
Data: []byte("xy"),
|
||||
Offset: 2,
|
||||
Data: []byte("obar"),
|
||||
}
|
||||
err := str.AddStreamFrame(&frame1)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
err = str.AddStreamFrame(&frame2)
|
||||
Expect(err).To(MatchError("OverlappingStreamData: start of gap in stream chunk"))
|
||||
b := make([]byte, 6)
|
||||
n, err := str.Read(b)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(n).To(Equal(6))
|
||||
Expect(b).To(Equal([]byte("foobar")))
|
||||
})
|
||||
|
||||
It("calls onData", func() {
|
||||
|
||||
Reference in New Issue
Block a user