Merge pull request #454 from lucas-clemente/streamframesorter

accept overlapping stream data
This commit is contained in:
Marten Seemann
2017-02-28 19:05:36 +07:00
committed by GitHub
3 changed files with 353 additions and 146 deletions

View File

@@ -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
}

View File

@@ -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)))
})
})

View File

@@ -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() {