fix splitting of STREAM frames for IETF QUIC

Move splitting of STREAM frames from the quic package to the wire
package.
This commit is contained in:
Marten Seemann 2018-02-05 11:50:36 +08:00
parent 5974c6c113
commit 80969de93f
39 changed files with 248 additions and 157 deletions

View file

@ -138,10 +138,10 @@ func (f *AckFrame) Write(b *bytes.Buffer, version protocol.VersionNumber) error
return nil
}
// MinLength of a written frame
func (f *AckFrame) MinLength(version protocol.VersionNumber) protocol.ByteCount {
// Length of a written frame
func (f *AckFrame) Length(version protocol.VersionNumber) protocol.ByteCount {
if !version.UsesIETFFrameFormat() {
return f.minLengthLegacy(version)
return f.lengthLegacy(version)
}
length := 1 + utils.VarIntLen(uint64(f.LargestAcked)) + utils.VarIntLen(uint64(encodeAckDelay(f.DelayTime)))

View file

@ -308,7 +308,7 @@ func (f *AckFrame) writeLegacy(b *bytes.Buffer, _ protocol.VersionNumber) error
return nil
}
func (f *AckFrame) minLengthLegacy(_ protocol.VersionNumber) protocol.ByteCount {
func (f *AckFrame) lengthLegacy(_ protocol.VersionNumber) protocol.ByteCount {
length := protocol.ByteCount(1 + 2 + 1) // 1 TypeByte, 2 ACK delay time, 1 Num Timestamp
length += protocol.ByteCount(protocol.GetPacketNumberLength(f.LargestAcked))

View file

@ -1067,7 +1067,7 @@ var _ = Describe("ACK Frame (for gQUIC)", func() {
}
err := f.Write(b, versionBigEndian)
Expect(err).ToNot(HaveOccurred())
Expect(f.MinLength(versionBigEndian)).To(Equal(protocol.ByteCount(b.Len())))
Expect(f.Length(versionBigEndian)).To(Equal(protocol.ByteCount(b.Len())))
})
It("has proper min length with a large LargestObserved", func() {
@ -1076,7 +1076,7 @@ var _ = Describe("ACK Frame (for gQUIC)", func() {
}
err := f.Write(b, versionBigEndian)
Expect(err).ToNot(HaveOccurred())
Expect(f.MinLength(versionBigEndian)).To(Equal(protocol.ByteCount(b.Len())))
Expect(f.Length(versionBigEndian)).To(Equal(protocol.ByteCount(b.Len())))
})
It("has the proper min length for an ACK with missing packets", func() {
@ -1091,7 +1091,7 @@ var _ = Describe("ACK Frame (for gQUIC)", func() {
}
err := f.Write(b, versionBigEndian)
Expect(err).ToNot(HaveOccurred())
Expect(f.MinLength(versionBigEndian)).To(Equal(protocol.ByteCount(b.Len())))
Expect(f.Length(versionBigEndian)).To(Equal(protocol.ByteCount(b.Len())))
})
It("has the proper min length for an ACK with long gaps of missing packets", func() {
@ -1106,7 +1106,7 @@ var _ = Describe("ACK Frame (for gQUIC)", func() {
}
err := f.Write(b, versionBigEndian)
Expect(err).ToNot(HaveOccurred())
Expect(f.MinLength(versionBigEndian)).To(Equal(protocol.ByteCount(b.Len())))
Expect(f.Length(versionBigEndian)).To(Equal(protocol.ByteCount(b.Len())))
})
It("has the proper min length for an ACK with a long ACK range", func() {
@ -1122,7 +1122,7 @@ var _ = Describe("ACK Frame (for gQUIC)", func() {
}
err := f.Write(b, versionBigEndian)
Expect(err).ToNot(HaveOccurred())
Expect(f.MinLength(versionBigEndian)).To(Equal(protocol.ByteCount(b.Len())))
Expect(f.Length(versionBigEndian)).To(Equal(protocol.ByteCount(b.Len())))
})
})
})

View file

@ -140,7 +140,7 @@ var _ = Describe("ACK Frame (for IETF QUIC)", func() {
}
err := f.Write(buf, versionIETFFrames)
Expect(err).ToNot(HaveOccurred())
Expect(f.MinLength(versionIETFFrames)).To(BeEquivalentTo(buf.Len()))
Expect(f.Length(versionIETFFrames)).To(BeEquivalentTo(buf.Len()))
b := bytes.NewReader(buf.Bytes())
frame, err := ParseAckFrame(b, versionIETFFrames)
Expect(err).ToNot(HaveOccurred())
@ -157,7 +157,7 @@ var _ = Describe("ACK Frame (for IETF QUIC)", func() {
}
err := f.Write(buf, versionIETFFrames)
Expect(err).ToNot(HaveOccurred())
Expect(f.MinLength(versionIETFFrames)).To(BeEquivalentTo(buf.Len()))
Expect(f.Length(versionIETFFrames)).To(BeEquivalentTo(buf.Len()))
b := bytes.NewReader(buf.Bytes())
frame, err := ParseAckFrame(b, versionIETFFrames)
Expect(err).ToNot(HaveOccurred())
@ -179,7 +179,7 @@ var _ = Describe("ACK Frame (for IETF QUIC)", func() {
Expect(f.validateAckRanges()).To(BeTrue())
err := f.Write(buf, versionIETFFrames)
Expect(err).ToNot(HaveOccurred())
Expect(f.MinLength(versionIETFFrames)).To(BeEquivalentTo(buf.Len()))
Expect(f.Length(versionIETFFrames)).To(BeEquivalentTo(buf.Len()))
b := bytes.NewReader(buf.Bytes())
frame, err := ParseAckFrame(b, versionIETFFrames)
Expect(err).ToNot(HaveOccurred())
@ -203,7 +203,7 @@ var _ = Describe("ACK Frame (for IETF QUIC)", func() {
Expect(f.validateAckRanges()).To(BeTrue())
err := f.Write(buf, versionIETFFrames)
Expect(err).ToNot(HaveOccurred())
Expect(f.MinLength(versionIETFFrames)).To(BeEquivalentTo(buf.Len()))
Expect(f.Length(versionIETFFrames)).To(BeEquivalentTo(buf.Len()))
b := bytes.NewReader(buf.Bytes())
frame, err := ParseAckFrame(b, versionIETFFrames)
Expect(err).ToNot(HaveOccurred())

View file

@ -36,8 +36,8 @@ func (f *BlockedFrame) Write(b *bytes.Buffer, version protocol.VersionNumber) er
return nil
}
// MinLength of a written frame
func (f *BlockedFrame) MinLength(version protocol.VersionNumber) protocol.ByteCount {
// Length of a written frame
func (f *BlockedFrame) Length(version protocol.VersionNumber) protocol.ByteCount {
if !version.UsesIETFFrameFormat() {
return 1 + 4
}

View file

@ -47,7 +47,7 @@ var _ = Describe("legacy BLOCKED Frame", func() {
It("has the correct min length for a BLOCKED frame for a stream", func() {
frame := StreamBlockedFrame{StreamID: 3}
Expect(frame.MinLength(versionBigEndian)).To(Equal(protocol.ByteCount(5)))
Expect(frame.Length(versionBigEndian)).To(Equal(protocol.ByteCount(5)))
})
It("writes a BLOCKED frame for the connection", func() {
@ -59,7 +59,7 @@ var _ = Describe("legacy BLOCKED Frame", func() {
It("has the correct min length for a BLOCKED frame for the connection", func() {
frame := BlockedFrame{}
Expect(frame.MinLength(versionBigEndian)).To(Equal(protocol.ByteCount(5)))
Expect(frame.Length(versionBigEndian)).To(Equal(protocol.ByteCount(5)))
})
})
})

View file

@ -48,7 +48,7 @@ var _ = Describe("BLOCKED frame", func() {
It("has the correct min length", func() {
frame := BlockedFrame{Offset: 0x12345}
Expect(frame.MinLength(versionIETFFrames)).To(Equal(1 + utils.VarIntLen(0x12345)))
Expect(frame.Length(versionIETFFrames)).To(Equal(1 + utils.VarIntLen(0x12345)))
})
})
})

View file

@ -67,8 +67,8 @@ func ParseConnectionCloseFrame(r *bytes.Reader, version protocol.VersionNumber)
}, nil
}
// MinLength of a written frame
func (f *ConnectionCloseFrame) MinLength(version protocol.VersionNumber) protocol.ByteCount {
// Length of a written frame
func (f *ConnectionCloseFrame) Length(version protocol.VersionNumber) protocol.ByteCount {
if version.UsesIETFFrameFormat() {
return 1 + 2 + utils.VarIntLen(uint64(len(f.ReasonPhrase))) + protocol.ByteCount(len(f.ReasonPhrase))
}

View file

@ -146,7 +146,7 @@ var _ = Describe("CONNECTION_CLOSE Frame", func() {
}
err := f.Write(b, versionIETFFrames)
Expect(err).ToNot(HaveOccurred())
Expect(f.MinLength(versionIETFFrames)).To(Equal(protocol.ByteCount(b.Len())))
Expect(f.Length(versionIETFFrames)).To(Equal(protocol.ByteCount(b.Len())))
})
})
@ -189,7 +189,7 @@ var _ = Describe("CONNECTION_CLOSE Frame", func() {
}
err := f.Write(b, versionBigEndian)
Expect(err).ToNot(HaveOccurred())
Expect(f.MinLength(versionBigEndian)).To(Equal(protocol.ByteCount(b.Len())))
Expect(f.Length(versionBigEndian)).To(Equal(protocol.ByteCount(b.Len())))
})
})
})

View file

@ -9,5 +9,5 @@ import (
// A Frame in QUIC
type Frame interface {
Write(b *bytes.Buffer, version protocol.VersionNumber) error
MinLength(version protocol.VersionNumber) protocol.ByteCount
Length(version protocol.VersionNumber) protocol.ByteCount
}

View file

@ -62,7 +62,7 @@ func (f *GoawayFrame) Write(b *bytes.Buffer, _ protocol.VersionNumber) error {
return nil
}
// MinLength of a written frame
func (f *GoawayFrame) MinLength(version protocol.VersionNumber) protocol.ByteCount {
// Length of a written frame
func (f *GoawayFrame) Length(version protocol.VersionNumber) protocol.ByteCount {
return protocol.ByteCount(1 + 4 + 4 + 2 + len(f.ReasonPhrase))
}

View file

@ -81,7 +81,7 @@ var _ = Describe("GoawayFrame", func() {
frame := GoawayFrame{
ReasonPhrase: "foo",
}
Expect(frame.MinLength(0)).To(Equal(protocol.ByteCount(14)))
Expect(frame.Length(0)).To(Equal(protocol.ByteCount(14)))
})
})
})

View file

@ -42,8 +42,8 @@ func (f *MaxDataFrame) Write(b *bytes.Buffer, version protocol.VersionNumber) er
return nil
}
// MinLength of a written frame
func (f *MaxDataFrame) MinLength(version protocol.VersionNumber) protocol.ByteCount {
// Length of a written frame
func (f *MaxDataFrame) Length(version protocol.VersionNumber) protocol.ByteCount {
if !version.UsesIETFFrameFormat() { // writing this frame would result in a gQUIC WINDOW_UPDATE being written, which is longer
return 1 + 4 + 8
}

View file

@ -38,7 +38,7 @@ var _ = Describe("MAX_DATA frame", func() {
f := &MaxDataFrame{
ByteOffset: 0xdeadbeef,
}
Expect(f.MinLength(versionIETFFrames)).To(Equal(1 + utils.VarIntLen(0xdeadbeef)))
Expect(f.Length(versionIETFFrames)).To(Equal(1 + utils.VarIntLen(0xdeadbeef)))
})
It("writes a MAX_DATA frame", func() {

View file

@ -50,8 +50,8 @@ func (f *MaxStreamDataFrame) Write(b *bytes.Buffer, version protocol.VersionNumb
return nil
}
// MinLength of a written frame
func (f *MaxStreamDataFrame) MinLength(version protocol.VersionNumber) protocol.ByteCount {
// Length of a written frame
func (f *MaxStreamDataFrame) Length(version protocol.VersionNumber) protocol.ByteCount {
// writing this frame would result in a gQUIC WINDOW_UPDATE being written, which has a different length
if !version.UsesIETFFrameFormat() {
return 1 + 4 + 8

View file

@ -42,7 +42,7 @@ var _ = Describe("MAX_STREAM_DATA frame", func() {
StreamID: 0x1337,
ByteOffset: 0xdeadbeef,
}
Expect(f.MinLength(protocol.VersionWhatever)).To(Equal(1 + utils.VarIntLen(uint64(f.StreamID)) + utils.VarIntLen(uint64(f.ByteOffset))))
Expect(f.Length(protocol.VersionWhatever)).To(Equal(1 + utils.VarIntLen(uint64(f.StreamID)) + utils.VarIntLen(uint64(f.ByteOffset))))
})
It("writes a sample frame", func() {

View file

@ -31,7 +31,7 @@ func (f *MaxStreamIDFrame) Write(b *bytes.Buffer, _ protocol.VersionNumber) erro
return nil
}
// MinLength of a written frame
func (f *MaxStreamIDFrame) MinLength(protocol.VersionNumber) protocol.ByteCount {
// Length of a written frame
func (f *MaxStreamIDFrame) Length(protocol.VersionNumber) protocol.ByteCount {
return 1 + utils.VarIntLen(uint64(f.StreamID))
}

View file

@ -45,7 +45,7 @@ var _ = Describe("MAX_STREAM_ID frame", func() {
It("has the correct min length", func() {
frame := MaxStreamIDFrame{StreamID: 0x1337}
Expect(frame.MinLength(protocol.VersionWhatever)).To(Equal(1 + utils.VarIntLen(0x1337)))
Expect(frame.Length(protocol.VersionWhatever)).To(Equal(1 + utils.VarIntLen(0x1337)))
})
})
})

View file

@ -27,7 +27,7 @@ func (f *PingFrame) Write(b *bytes.Buffer, version protocol.VersionNumber) error
return nil
}
// MinLength of a written frame
func (f *PingFrame) MinLength(version protocol.VersionNumber) protocol.ByteCount {
// Length of a written frame
func (f *PingFrame) Length(version protocol.VersionNumber) protocol.ByteCount {
return 1
}

View file

@ -33,7 +33,7 @@ var _ = Describe("PingFrame", func() {
It("has the correct min length", func() {
frame := PingFrame{}
Expect(frame.MinLength(0)).To(Equal(protocol.ByteCount(1)))
Expect(frame.Length(0)).To(Equal(protocol.ByteCount(1)))
})
})
})

View file

@ -80,8 +80,8 @@ func (f *RstStreamFrame) Write(b *bytes.Buffer, version protocol.VersionNumber)
return nil
}
// MinLength of a written frame
func (f *RstStreamFrame) MinLength(version protocol.VersionNumber) protocol.ByteCount {
// Length of a written frame
func (f *RstStreamFrame) Length(version protocol.VersionNumber) protocol.ByteCount {
if version.UsesIETFFrameFormat() {
return 1 + utils.VarIntLen(uint64(f.StreamID)) + 2 + utils.VarIntLen(uint64(f.ByteOffset))
}

View file

@ -94,7 +94,7 @@ var _ = Describe("RST_STREAM frame", func() {
ErrorCode: 0xde,
}
expectedLen := 1 + utils.VarIntLen(0x1337) + utils.VarIntLen(0x1234567) + 2
Expect(rst.MinLength(versionIETFFrames)).To(Equal(expectedLen))
Expect(rst.Length(versionIETFFrames)).To(Equal(expectedLen))
})
})
@ -121,7 +121,7 @@ var _ = Describe("RST_STREAM frame", func() {
ByteOffset: 0x1000,
ErrorCode: 0xde,
}
Expect(rst.MinLength(versionBigEndian)).To(Equal(protocol.ByteCount(17)))
Expect(rst.Length(versionBigEndian)).To(Equal(protocol.ByteCount(17)))
})
})
})

View file

@ -34,8 +34,8 @@ func ParseStopSendingFrame(r *bytes.Reader, _ protocol.VersionNumber) (*StopSend
}, nil
}
// MinLength of a written frame
func (f *StopSendingFrame) MinLength(_ protocol.VersionNumber) protocol.ByteCount {
// Length of a written frame
func (f *StopSendingFrame) Length(_ protocol.VersionNumber) protocol.ByteCount {
return 1 + utils.VarIntLen(uint64(f.StreamID)) + 2
}

View file

@ -57,7 +57,7 @@ var _ = Describe("STOP_SENDING frame", func() {
StreamID: 0xdeadbeef,
ErrorCode: 0x10,
}
Expect(frame.MinLength(versionIETFFrames)).To(Equal(1 + 2 + utils.VarIntLen(0xdeadbeef)))
Expect(frame.Length(versionIETFFrames)).To(Equal(1 + 2 + utils.VarIntLen(0xdeadbeef)))
})
})
})

View file

@ -51,8 +51,8 @@ func (f *StopWaitingFrame) Write(b *bytes.Buffer, v protocol.VersionNumber) erro
return nil
}
// MinLength of a written frame
func (f *StopWaitingFrame) MinLength(_ protocol.VersionNumber) protocol.ByteCount {
// Length of a written frame
func (f *StopWaitingFrame) Length(_ protocol.VersionNumber) protocol.ByteCount {
return 1 + protocol.ByteCount(f.PacketNumberLen)
}

View file

@ -177,14 +177,14 @@ var _ = Describe("StopWaitingFrame", func() {
})
})
Context("minLength", func() {
It("calculates the right minLength", func() {
Context("Length", func() {
It("calculates the right length", func() {
for _, length := range []protocol.PacketNumberLen{protocol.PacketNumberLen1, protocol.PacketNumberLen2, protocol.PacketNumberLen4, protocol.PacketNumberLen6} {
frame := &StopWaitingFrame{
LeastUnacked: 10,
PacketNumberLen: length,
}
Expect(frame.MinLength(protocol.VersionWhatever)).To(Equal(protocol.ByteCount(length + 1)))
Expect(frame.Length(protocol.VersionWhatever)).To(Equal(protocol.ByteCount(length + 1)))
}
})
})

View file

@ -43,8 +43,8 @@ func (f *StreamBlockedFrame) Write(b *bytes.Buffer, version protocol.VersionNumb
return nil
}
// MinLength of a written frame
func (f *StreamBlockedFrame) MinLength(version protocol.VersionNumber) protocol.ByteCount {
// Length of a written frame
func (f *StreamBlockedFrame) Length(version protocol.VersionNumber) protocol.ByteCount {
if !version.UsesIETFFrameFormat() {
return 1 + 4
}

View file

@ -43,7 +43,7 @@ var _ = Describe("STREAM_BLOCKED frame", func() {
StreamID: 0x1337,
Offset: 0xdeadbeef,
}
Expect(f.MinLength(0)).To(Equal(1 + utils.VarIntLen(0x1337) + utils.VarIntLen(0xdeadbeef)))
Expect(f.Length(0)).To(Equal(1 + utils.VarIntLen(0x1337) + utils.VarIntLen(0xdeadbeef)))
})
It("writes a sample frame", func() {

View file

@ -115,11 +115,10 @@ func (f *StreamFrame) Write(b *bytes.Buffer, version protocol.VersionNumber) err
return nil
}
// MinLength returns the length of the header of a StreamFrame
// the total length of the frame is frame.MinLength() + frame.DataLen()
func (f *StreamFrame) MinLength(version protocol.VersionNumber) protocol.ByteCount {
// Length returns the total length of the STREAM frame
func (f *StreamFrame) Length(version protocol.VersionNumber) protocol.ByteCount {
if !version.UsesIETFFrameFormat() {
return f.minLengthLegacy(version)
return f.lengthLegacy(version)
}
length := 1 + utils.VarIntLen(uint64(f.StreamID))
if f.Offset != 0 {
@ -128,11 +127,11 @@ func (f *StreamFrame) MinLength(version protocol.VersionNumber) protocol.ByteCou
if f.DataLenPresent {
length += utils.VarIntLen(uint64(f.DataLen()))
}
return length
return length + f.DataLen()
}
// MaxDataLen returns the maximum data length
// If 0 is returned, writing will fail (a STREAM_FRAME must contain at least 1 byte of data).
// If 0 is returned, writing will fail (a STREAM frame must contain at least 1 byte of data).
func (f *StreamFrame) MaxDataLen(maxSize protocol.ByteCount, version protocol.VersionNumber) protocol.ByteCount {
if !version.UsesIETFFrameFormat() {
return f.maxDataLenLegacy(maxSize, version)
@ -156,3 +155,28 @@ func (f *StreamFrame) MaxDataLen(maxSize protocol.ByteCount, version protocol.Ve
}
return maxDataLen
}
// MaybeSplitOffFrame splits a frame such that it is not bigger than n bytes.
// If n >= len(frame), nil is returned and nothing is modified.
func (f *StreamFrame) MaybeSplitOffFrame(maxSize protocol.ByteCount, version protocol.VersionNumber) (*StreamFrame, error) {
if maxSize >= f.Length(version) {
return nil, nil
}
n := f.MaxDataLen(maxSize, version)
if n == 0 {
return nil, errors.New("too small")
}
newFrame := &StreamFrame{
FinBit: false,
StreamID: f.StreamID,
Offset: f.Offset,
Data: f.Data[:n],
DataLenPresent: f.DataLenPresent,
}
f.Data = f.Data[n:]
f.Offset += n
return newFrame, nil
}

View file

@ -183,7 +183,7 @@ func (f *StreamFrame) getOffsetLength() protocol.ByteCount {
return 8
}
func (f *StreamFrame) minLengthLegacy(_ protocol.VersionNumber) protocol.ByteCount {
func (f *StreamFrame) headerLengthLegacy(_ protocol.VersionNumber) protocol.ByteCount {
length := protocol.ByteCount(1) + protocol.ByteCount(f.calculateStreamIDLength()) + f.getOffsetLength()
if f.DataLenPresent {
length += 2
@ -191,8 +191,12 @@ func (f *StreamFrame) minLengthLegacy(_ protocol.VersionNumber) protocol.ByteCou
return length
}
func (f *StreamFrame) lengthLegacy(version protocol.VersionNumber) protocol.ByteCount {
return f.headerLengthLegacy(version) + f.DataLen()
}
func (f *StreamFrame) maxDataLenLegacy(maxFrameSize protocol.ByteCount, version protocol.VersionNumber) protocol.ByteCount {
headerLen := f.minLengthLegacy(version)
headerLen := f.headerLengthLegacy(version)
if headerLen > maxFrameSize {
return 0
}

View file

@ -182,7 +182,7 @@ var _ = Describe("STREAM frame (for gQUIC)", func() {
}
err := f.Write(b, versionBigEndian)
Expect(err).ToNot(HaveOccurred())
Expect(f.MinLength(0)).To(Equal(protocol.ByteCount(b.Len())))
Expect(f.Length(0)).To(Equal(protocol.ByteCount(b.Len())))
})
It("has proper min length for a long StreamID and a big offset", func() {
@ -195,7 +195,7 @@ var _ = Describe("STREAM frame (for gQUIC)", func() {
}
err := f.Write(b, versionBigEndian)
Expect(err).ToNot(HaveOccurred())
Expect(f.MinLength(versionBigEndian)).To(Equal(protocol.ByteCount(b.Len())))
Expect(f.Length(versionBigEndian)).To(Equal(protocol.ByteCount(b.Len())))
})
Context("data length field", func() {
@ -210,9 +210,11 @@ var _ = Describe("STREAM frame (for gQUIC)", func() {
}
err := f.Write(b, versionBigEndian)
Expect(err).ToNot(HaveOccurred())
minLength := f.MinLength(0)
Expect(b.Bytes()[0] & 0x20).To(Equal(uint8(0x20)))
Expect(b.Bytes()[minLength-2 : minLength]).To(Equal([]byte{0x13, 0x37}))
frame, err := ParseStreamFrame(bytes.NewReader(b.Bytes()), versionBigEndian)
Expect(err).ToNot(HaveOccurred())
Expect(frame.DataLenPresent).To(BeTrue())
Expect(frame.DataLen()).To(Equal(protocol.ByteCount(dataLen)))
})
})
@ -229,10 +231,10 @@ var _ = Describe("STREAM frame (for gQUIC)", func() {
Expect(err).ToNot(HaveOccurred())
Expect(b.Bytes()[0] & 0x20).To(Equal(uint8(0)))
Expect(b.Bytes()[1 : b.Len()-dataLen]).ToNot(ContainSubstring(string([]byte{0x37, 0x13})))
minLength := f.MinLength(versionBigEndian)
length := f.Length(versionBigEndian)
f.DataLenPresent = true
minLengthWithoutDataLen := f.MinLength(versionBigEndian)
Expect(minLength).To(Equal(minLengthWithoutDataLen - 2))
lengthWithoutDataLen := f.Length(versionBigEndian)
Expect(length).To(Equal(lengthWithoutDataLen - 2))
})
It("calculates the correct min-length", func() {
@ -242,9 +244,9 @@ var _ = Describe("STREAM frame (for gQUIC)", func() {
DataLenPresent: false,
Offset: 0xdeadbeef,
}
minLengthWithoutDataLen := f.MinLength(versionBigEndian)
lengthWithoutDataLen := f.Length(versionBigEndian)
f.DataLenPresent = true
Expect(f.MinLength(versionBigEndian)).To(Equal(minLengthWithoutDataLen + 2))
Expect(f.Length(versionBigEndian)).To(Equal(lengthWithoutDataLen + 2))
})
Context("offset lengths", func() {
@ -495,8 +497,8 @@ var _ = Describe("STREAM frame (for gQUIC)", func() {
b.Reset()
f.Data = nil
maxDataLen := f.MaxDataLen(protocol.ByteCount(i), versionBigEndian)
if maxDataLen == 0 { // 0 means that no valid STREAM_FRAME can be written
// check that writing a minimal size STREAM_FRAME (i.e. with 1 byte data) is actually larger than the desired size
if maxDataLen == 0 { // 0 means that no valid STREAM frame can be written
// check that writing a minimal size STREAM frame (i.e. with 1 byte data) is actually larger than the desired size
f.Data = []byte{0}
err := f.Write(b, versionBigEndian)
Expect(err).ToNot(HaveOccurred())

View file

@ -186,7 +186,7 @@ var _ = Describe("STREAM frame (for IETF QUIC)", func() {
StreamID: 0x1337,
Data: []byte("foobar"),
}
Expect(f.MinLength(versionIETFFrames)).To(Equal(1 + utils.VarIntLen(0x1337)))
Expect(f.Length(versionIETFFrames)).To(Equal(1 + utils.VarIntLen(0x1337) + 6))
})
It("has the right length for a frame with offset", func() {
@ -195,7 +195,7 @@ var _ = Describe("STREAM frame (for IETF QUIC)", func() {
Offset: 0x42,
Data: []byte("foobar"),
}
Expect(f.MinLength(versionIETFFrames)).To(Equal(1 + utils.VarIntLen(0x1337) + utils.VarIntLen(0x42)))
Expect(f.Length(versionIETFFrames)).To(Equal(1 + utils.VarIntLen(0x1337) + utils.VarIntLen(0x42) + 6))
})
It("has the right length for a frame with data length", func() {
@ -205,7 +205,7 @@ var _ = Describe("STREAM frame (for IETF QUIC)", func() {
DataLenPresent: true,
Data: []byte("foobar"),
}
Expect(f.MinLength(versionIETFFrames)).To(Equal(1 + utils.VarIntLen(0x1337) + utils.VarIntLen(0x1234567) + utils.VarIntLen(6)))
Expect(f.Length(versionIETFFrames)).To(Equal(1 + utils.VarIntLen(0x1337) + utils.VarIntLen(0x1234567) + utils.VarIntLen(6) + 6))
})
})
@ -223,8 +223,8 @@ var _ = Describe("STREAM frame (for IETF QUIC)", func() {
b.Reset()
f.Data = nil
maxDataLen := f.MaxDataLen(protocol.ByteCount(i), versionIETFFrames)
if maxDataLen == 0 { // 0 means that no valid STREAM_FRAME can be written
// check that writing a minimal size STREAM_FRAME (i.e. with 1 byte data) is actually larger than the desired size
if maxDataLen == 0 { // 0 means that no valid STREAM frame can be written
// check that writing a minimal size STREAM frame (i.e. with 1 byte data) is actually larger than the desired size
f.Data = []byte{0}
err := f.Write(b, versionIETFFrames)
Expect(err).ToNot(HaveOccurred())
@ -251,8 +251,8 @@ var _ = Describe("STREAM frame (for IETF QUIC)", func() {
b.Reset()
f.Data = nil
maxDataLen := f.MaxDataLen(protocol.ByteCount(i), versionIETFFrames)
if maxDataLen == 0 { // 0 means that no valid STREAM_FRAME can be written
// check that writing a minimal size STREAM_FRAME (i.e. with 1 byte data) is actually larger than the desired size
if maxDataLen == 0 { // 0 means that no valid STREAM frame can be written
// check that writing a minimal size STREAM frame (i.e. with 1 byte data) is actually larger than the desired size
f.Data = []byte{0}
err := f.Write(b, versionIETFFrames)
Expect(err).ToNot(HaveOccurred())
@ -264,7 +264,7 @@ var _ = Describe("STREAM frame (for IETF QUIC)", func() {
Expect(err).ToNot(HaveOccurred())
// There's *one* pathological case, where a data length of x can be encoded into 1 byte
// but a data lengths of x+1 needs 2 bytes
// In that case, it's impossible to create a STREAM_FRAME of the desired size
// In that case, it's impossible to create a STREAM frame of the desired size
if b.Len() == i-1 {
frameOneByteTooSmallCounter++
continue
@ -274,4 +274,118 @@ var _ = Describe("STREAM frame (for IETF QUIC)", func() {
Expect(frameOneByteTooSmallCounter).To(Equal(1))
})
})
Context("splitting", func() {
for _, v := range []protocol.VersionNumber{versionBigEndian, versionIETFFrames} {
version := v
It("doesn't split if the frame is short enough", func() {
f := &StreamFrame{
StreamID: 0x1337,
DataLenPresent: true,
Offset: 0xdeadbeef,
Data: make([]byte, 100),
}
newFrame, err := f.MaybeSplitOffFrame(f.Length(version), version)
Expect(err).ToNot(HaveOccurred())
Expect(newFrame).To(BeNil())
newFrame, err = f.MaybeSplitOffFrame(f.Length(version)-1, version)
Expect(err).ToNot(HaveOccurred())
Expect(newFrame).ToNot(BeNil())
})
It("keeps the data len", func() {
f := &StreamFrame{
StreamID: 0x1337,
DataLenPresent: true,
Data: make([]byte, 100),
}
newFrame, err := f.MaybeSplitOffFrame(66, version)
Expect(err).ToNot(HaveOccurred())
Expect(newFrame).ToNot(BeNil())
Expect(f.DataLenPresent).To(BeTrue())
Expect(newFrame.DataLenPresent).To(BeTrue())
})
It("adjusts the offset", func() {
f := &StreamFrame{
StreamID: 0x1337,
Offset: 0x100,
Data: []byte("foobar"),
}
newFrame, err := f.MaybeSplitOffFrame(f.Length(version)-3, version)
Expect(err).ToNot(HaveOccurred())
Expect(newFrame).ToNot(BeNil())
Expect(newFrame.Offset).To(Equal(protocol.ByteCount(0x100)))
Expect(newFrame.Data).To(Equal([]byte("foo")))
Expect(f.Offset).To(Equal(protocol.ByteCount(0x100 + 3)))
Expect(f.Data).To(Equal([]byte("bar")))
})
It("preserves the FIN bit", func() {
f := &StreamFrame{
StreamID: 0x1337,
FinBit: true,
Offset: 0xdeadbeef,
Data: make([]byte, 100),
}
newFrame, err := f.MaybeSplitOffFrame(50, version)
Expect(err).ToNot(HaveOccurred())
Expect(newFrame).ToNot(BeNil())
Expect(newFrame.Offset).To(BeNumerically("<", f.Offset))
Expect(f.FinBit).To(BeTrue())
Expect(newFrame.FinBit).To(BeFalse())
})
It("produces frames of the correct length, without data len", func() {
const size = 1000
f := &StreamFrame{
StreamID: 0xdecafbad,
Offset: 0x1234,
Data: []byte{0},
}
minFrameSize := f.Length(version)
for i := protocol.ByteCount(0); i < minFrameSize; i++ {
_, err := f.MaybeSplitOffFrame(i, version)
Expect(err).To(HaveOccurred())
}
for i := minFrameSize; i < size; i++ {
f.Data = make([]byte, size)
newFrame, err := f.MaybeSplitOffFrame(i, version)
Expect(err).ToNot(HaveOccurred())
Expect(newFrame.Length(version)).To(Equal(i))
}
})
}
It("produces frames of the correct length, with data len", func() {
const size = 1000
f := &StreamFrame{
StreamID: 0xdecafbad,
Offset: 0x1234,
DataLenPresent: true,
Data: []byte{0},
}
minFrameSize := f.Length(versionIETFFrames)
for i := protocol.ByteCount(0); i < minFrameSize; i++ {
_, err := f.MaybeSplitOffFrame(i, versionIETFFrames)
Expect(err).To(HaveOccurred())
}
var frameOneByteTooSmallCounter int
for i := minFrameSize; i < size; i++ {
f.Data = make([]byte, size)
newFrame, err := f.MaybeSplitOffFrame(i, versionIETFFrames)
Expect(err).ToNot(HaveOccurred())
// There's *one* pathological case, where a data length of x can be encoded into 1 byte
// but a data lengths of x+1 needs 2 bytes
// In that case, it's impossible to create a STREAM frame of the desired size
if newFrame.Length(versionIETFFrames) == i-1 {
frameOneByteTooSmallCounter++
continue
}
Expect(newFrame.Length(versionIETFFrames)).To(Equal(i))
}
Expect(frameOneByteTooSmallCounter).To(Equal(1))
})
})
})

View file

@ -31,7 +31,7 @@ func (f *StreamIDBlockedFrame) Write(b *bytes.Buffer, _ protocol.VersionNumber)
return nil
}
// MinLength of a written frame
func (f *StreamIDBlockedFrame) MinLength(_ protocol.VersionNumber) protocol.ByteCount {
// Length of a written frame
func (f *StreamIDBlockedFrame) Length(_ protocol.VersionNumber) protocol.ByteCount {
return 1 + utils.VarIntLen(uint64(f.StreamID))
}

View file

@ -47,7 +47,7 @@ var _ = Describe("STREAM_ID_BLOCKED frame", func() {
It("has the correct min length", func() {
frame := StreamIDBlockedFrame{StreamID: 0x123456}
Expect(frame.MinLength(0)).To(Equal(protocol.ByteCount(1) + utils.VarIntLen(0x123456)))
Expect(frame.Length(0)).To(Equal(protocol.ByteCount(1) + utils.VarIntLen(0x123456)))
})
})
})

View file

@ -56,14 +56,14 @@ var _ = Describe("WINDOW_UPDATE frame", func() {
f := &MaxDataFrame{
ByteOffset: 0xdeadbeef,
}
Expect(f.MinLength(versionBigEndian)).To(Equal(protocol.ByteCount(1 + 4 + 8)))
Expect(f.Length(versionBigEndian)).To(Equal(protocol.ByteCount(1 + 4 + 8)))
})
It("has the proper min length for the connection-level WINDOW_UPDATE frame", func() {
f := &MaxDataFrame{
ByteOffset: 0xdeadbeef,
}
Expect(f.MinLength(versionBigEndian)).To(Equal(protocol.ByteCount(1 + 4 + 8)))
Expect(f.Length(versionBigEndian)).To(Equal(protocol.ByteCount(1 + 4 + 8)))
})
Context("in big endian", func() {

View file

@ -230,23 +230,23 @@ func (p *packetPacker) composeNextPacket(
// STOP_WAITING and ACK will always fit
if p.ackFrame != nil { // ACKs need to go first, so that the sentPacketHandler will recognize them
payloadFrames = append(payloadFrames, p.ackFrame)
l := p.ackFrame.MinLength(p.version)
l := p.ackFrame.Length(p.version)
payloadLength += l
}
if p.stopWaiting != nil { // a STOP_WAITING will only be queued when using gQUIC
payloadFrames = append(payloadFrames, p.stopWaiting)
payloadLength += p.stopWaiting.MinLength(p.version)
payloadLength += p.stopWaiting.Length(p.version)
}
p.controlFrameMutex.Lock()
for len(p.controlFrames) > 0 {
frame := p.controlFrames[len(p.controlFrames)-1]
minLength := frame.MinLength(p.version)
if payloadLength+minLength > maxFrameSize {
length := frame.Length(p.version)
if payloadLength+length > maxFrameSize {
break
}
payloadFrames = append(payloadFrames, frame)
payloadLength += minLength
payloadLength += length
p.controlFrames = p.controlFrames[:len(p.controlFrames)-1]
}
p.controlFrameMutex.Unlock()

View file

@ -345,7 +345,7 @@ var _ = Describe("Packet packer", func() {
It("packs a lot of control frames into 2 packets if they don't fit into one", func() {
blockedFrame := &wire.BlockedFrame{}
maxFramesPerPacket := int(maxFrameSize) / int(blockedFrame.MinLength(packer.version))
maxFramesPerPacket := int(maxFrameSize) / int(blockedFrame.Length(packer.version))
var controlFrames []wire.Frame
for i := 0; i < maxFramesPerPacket+10; i++ {
controlFrames = append(controlFrames, blockedFrame)
@ -445,7 +445,7 @@ var _ = Describe("Packet packer", func() {
StreamID: 5,
DataLenPresent: true,
}
f.Data = bytes.Repeat([]byte{'f'}, int(maxSize-f.MinLength(packer.version)))
f.Data = bytes.Repeat([]byte{'f'}, int(maxSize-f.Length(packer.version)))
return []*wire.StreamFrame{f}
})
mockStreamFramer.EXPECT().PopStreamFrames(gomock.Any())
@ -468,7 +468,7 @@ var _ = Describe("Packet packer", func() {
StreamID: 5,
DataLenPresent: true,
}
f.Data = bytes.Repeat([]byte{'f'}, int(maxSize-f.MinLength(packer.version)))
f.Data = bytes.Repeat([]byte{'f'}, int(maxSize-f.Length(packer.version)))
return []*wire.StreamFrame{f}
})
mockStreamFramer.EXPECT().PopStreamFrames(gomock.Any())

View file

@ -81,22 +81,24 @@ func (f *streamFramer) maybePopFramesForRetransmission(maxTotalLen protocol.Byte
frame := f.retransmissionQueue[0]
frame.DataLenPresent = true
frameHeaderLen := frame.MinLength(f.version) // can never error
maxLen := maxTotalLen - currentLen
if frameHeaderLen+frame.DataLen() > maxLen && maxLen < protocol.MinStreamFrameSize {
if frame.Length(f.version) > maxLen && maxLen < protocol.MinStreamFrameSize {
break
}
splitFrame := maybeSplitOffFrame(frame, maxLen-frameHeaderLen)
if splitFrame != nil { // StreamFrame was split
splitFrame, err := frame.MaybeSplitOffFrame(maxLen, f.version)
if err != nil { // maxLen is too small. Can't split frame
break
}
if splitFrame != nil { // frame was split
res = append(res, splitFrame)
currentLen += frameHeaderLen + splitFrame.DataLen()
currentLen += splitFrame.Length(f.version)
break
}
f.retransmissionQueue = f.retransmissionQueue[1:]
res = append(res, frame)
currentLen += frameHeaderLen + frame.DataLen()
currentLen += frame.Length(f.version)
}
return
}
@ -131,28 +133,8 @@ func (f *streamFramer) maybePopNormalFrames(maxTotalLen protocol.ByteCount) []*w
continue
}
frames = append(frames, frame)
currentLen += frame.MinLength(f.version) + frame.DataLen()
currentLen += frame.Length(f.version)
}
f.streamQueueMutex.Unlock()
return frames
}
// maybeSplitOffFrame removes the first n bytes and returns them as a separate frame. If n >= len(frame), nil is returned and nothing is modified.
func maybeSplitOffFrame(frame *wire.StreamFrame, n protocol.ByteCount) *wire.StreamFrame {
if n >= frame.DataLen() {
return nil
}
defer func() {
frame.Data = frame.Data[n:]
frame.Offset += n
}()
return &wire.StreamFrame{
FinBit: false,
StreamID: frame.StreamID,
Offset: frame.Offset,
Data: frame.Data[:n],
DataLenPresent: frame.DataLenPresent,
}
}

View file

@ -268,46 +268,11 @@ var _ = Describe("Stream Framer", func() {
})
Context("splitting of frames", func() {
It("splits off nothing", func() {
f := &wire.StreamFrame{
StreamID: 1,
Data: []byte("bar"),
Offset: 3,
}
Expect(maybeSplitOffFrame(f, 1000)).To(BeNil())
Expect(f.Offset).To(Equal(protocol.ByteCount(3)))
Expect(f.Data).To(Equal([]byte("bar")))
})
It("splits off initial frame", func() {
f := &wire.StreamFrame{
StreamID: 1,
Data: []byte("foobar"),
DataLenPresent: true,
Offset: 3,
FinBit: true,
}
previous := maybeSplitOffFrame(f, 3)
Expect(previous).ToNot(BeNil())
Expect(previous.StreamID).To(Equal(protocol.StreamID(1)))
Expect(previous.Data).To(Equal([]byte("foo")))
Expect(previous.DataLenPresent).To(BeTrue())
Expect(previous.Offset).To(Equal(protocol.ByteCount(3)))
Expect(previous.FinBit).To(BeFalse())
Expect(f.StreamID).To(Equal(protocol.StreamID(1)))
Expect(f.Data).To(Equal([]byte("bar")))
Expect(f.DataLenPresent).To(BeTrue())
Expect(f.Offset).To(Equal(protocol.ByteCount(6)))
Expect(f.FinBit).To(BeTrue())
})
It("splits a frame", func() {
frame := &wire.StreamFrame{Data: bytes.Repeat([]byte{0}, 600)}
framer.AddFrameForRetransmission(frame)
framer.AddFrameForRetransmission(&wire.StreamFrame{Data: make([]byte, 600)})
fs := framer.PopStreamFrames(500)
Expect(fs).To(HaveLen(1))
minLength := fs[0].MinLength(framer.version)
Expect(minLength + fs[0].DataLen()).To(Equal(protocol.ByteCount(500)))
Expect(fs[0].Length(framer.version)).To(Equal(protocol.ByteCount(500)))
Expect(framer.retransmissionQueue[0].Data).To(HaveLen(int(600 - fs[0].DataLen())))
Expect(framer.retransmissionQueue[0].Offset).To(Equal(fs[0].DataLen()))
})