github.com/apernet/quic-go@v0.43.1-0.20240515053213-5e9e635fd9f0/internal/wire/stream_frame_test.go (about) 1 package wire 2 3 import ( 4 "bytes" 5 "io" 6 7 "github.com/apernet/quic-go/internal/protocol" 8 "github.com/apernet/quic-go/quicvarint" 9 10 . "github.com/onsi/ginkgo/v2" 11 . "github.com/onsi/gomega" 12 ) 13 14 var _ = Describe("STREAM frame", func() { 15 Context("when parsing", func() { 16 It("parses a frame with OFF bit", func() { 17 data := encodeVarInt(0x12345) // stream ID 18 data = append(data, encodeVarInt(0xdecafbad)...) // offset 19 data = append(data, []byte("foobar")...) 20 r := bytes.NewReader(data) 21 frame, err := parseStreamFrame(r, 0x8^0x4, protocol.Version1) 22 Expect(err).ToNot(HaveOccurred()) 23 Expect(frame.StreamID).To(Equal(protocol.StreamID(0x12345))) 24 Expect(frame.Data).To(Equal([]byte("foobar"))) 25 Expect(frame.Fin).To(BeFalse()) 26 Expect(frame.Offset).To(Equal(protocol.ByteCount(0xdecafbad))) 27 Expect(r.Len()).To(BeZero()) 28 }) 29 30 It("respects the LEN when parsing the frame", func() { 31 data := encodeVarInt(0x12345) // stream ID 32 data = append(data, encodeVarInt(4)...) // data length 33 data = append(data, []byte("foobar")...) 34 r := bytes.NewReader(data) 35 frame, err := parseStreamFrame(r, 0x8^0x2, protocol.Version1) 36 Expect(err).ToNot(HaveOccurred()) 37 Expect(frame.StreamID).To(Equal(protocol.StreamID(0x12345))) 38 Expect(frame.Data).To(Equal([]byte("foob"))) 39 Expect(frame.Fin).To(BeFalse()) 40 Expect(frame.Offset).To(BeZero()) 41 Expect(r.Len()).To(Equal(2)) 42 }) 43 44 It("parses a frame with FIN bit", func() { 45 data := encodeVarInt(9) // stream ID 46 data = append(data, []byte("foobar")...) 47 r := bytes.NewReader(data) 48 frame, err := parseStreamFrame(r, 0x8^0x1, protocol.Version1) 49 Expect(err).ToNot(HaveOccurred()) 50 Expect(frame.StreamID).To(Equal(protocol.StreamID(9))) 51 Expect(frame.Data).To(Equal([]byte("foobar"))) 52 Expect(frame.Fin).To(BeTrue()) 53 Expect(frame.Offset).To(BeZero()) 54 Expect(r.Len()).To(BeZero()) 55 }) 56 57 It("allows empty frames", func() { 58 data := encodeVarInt(0x1337) // stream ID 59 data = append(data, encodeVarInt(0x12345)...) // offset 60 r := bytes.NewReader(data) 61 f, err := parseStreamFrame(r, 0x8^0x4, protocol.Version1) 62 Expect(err).ToNot(HaveOccurred()) 63 Expect(f.StreamID).To(Equal(protocol.StreamID(0x1337))) 64 Expect(f.Offset).To(Equal(protocol.ByteCount(0x12345))) 65 Expect(f.Data).To(BeEmpty()) 66 Expect(f.Fin).To(BeFalse()) 67 }) 68 69 It("rejects frames that overflow the maximum offset", func() { 70 data := encodeVarInt(0x12345) // stream ID 71 data = append(data, encodeVarInt(uint64(protocol.MaxByteCount-5))...) // offset 72 data = append(data, []byte("foobar")...) 73 r := bytes.NewReader(data) 74 _, err := parseStreamFrame(r, 0x8^0x4, protocol.Version1) 75 Expect(err).To(MatchError("stream data overflows maximum offset")) 76 }) 77 78 It("rejects frames that claim to be longer than the packet size", func() { 79 data := encodeVarInt(0x12345) // stream ID 80 data = append(data, encodeVarInt(uint64(protocol.MaxPacketBufferSize)+1)...) // data length 81 data = append(data, make([]byte, protocol.MaxPacketBufferSize+1)...) 82 r := bytes.NewReader(data) 83 _, err := parseStreamFrame(r, 0x8^0x2, protocol.Version1) 84 Expect(err).To(Equal(io.EOF)) 85 }) 86 87 It("errors on EOFs", func() { 88 typ := uint64(0x8 ^ 0x4 ^ 0x2) 89 data := encodeVarInt(0x12345) // stream ID 90 data = append(data, encodeVarInt(0xdecafbad)...) // offset 91 data = append(data, encodeVarInt(6)...) // data length 92 data = append(data, []byte("foobar")...) 93 _, err := parseStreamFrame(bytes.NewReader(data), typ, protocol.Version1) 94 Expect(err).NotTo(HaveOccurred()) 95 for i := range data { 96 _, err = parseStreamFrame(bytes.NewReader(data[:i]), typ, protocol.Version1) 97 Expect(err).To(HaveOccurred()) 98 } 99 }) 100 }) 101 102 Context("using the buffer", func() { 103 It("uses the buffer for long STREAM frames", func() { 104 data := encodeVarInt(0x12345) // stream ID 105 data = append(data, bytes.Repeat([]byte{'f'}, protocol.MinStreamFrameBufferSize)...) 106 r := bytes.NewReader(data) 107 frame, err := parseStreamFrame(r, 0x8, protocol.Version1) 108 Expect(err).ToNot(HaveOccurred()) 109 Expect(frame.StreamID).To(Equal(protocol.StreamID(0x12345))) 110 Expect(frame.Data).To(Equal(bytes.Repeat([]byte{'f'}, protocol.MinStreamFrameBufferSize))) 111 Expect(frame.DataLen()).To(BeEquivalentTo(protocol.MinStreamFrameBufferSize)) 112 Expect(frame.Fin).To(BeFalse()) 113 Expect(frame.fromPool).To(BeTrue()) 114 Expect(r.Len()).To(BeZero()) 115 Expect(frame.PutBack).ToNot(Panic()) 116 }) 117 118 It("doesn't use the buffer for short STREAM frames", func() { 119 data := encodeVarInt(0x12345) // stream ID 120 data = append(data, bytes.Repeat([]byte{'f'}, protocol.MinStreamFrameBufferSize-1)...) 121 r := bytes.NewReader(data) 122 frame, err := parseStreamFrame(r, 0x8, protocol.Version1) 123 Expect(err).ToNot(HaveOccurred()) 124 Expect(frame.StreamID).To(Equal(protocol.StreamID(0x12345))) 125 Expect(frame.Data).To(Equal(bytes.Repeat([]byte{'f'}, protocol.MinStreamFrameBufferSize-1))) 126 Expect(frame.DataLen()).To(BeEquivalentTo(protocol.MinStreamFrameBufferSize - 1)) 127 Expect(frame.Fin).To(BeFalse()) 128 Expect(frame.fromPool).To(BeFalse()) 129 Expect(r.Len()).To(BeZero()) 130 Expect(frame.PutBack).ToNot(Panic()) 131 }) 132 }) 133 134 Context("when writing", func() { 135 It("writes a frame without offset", func() { 136 f := &StreamFrame{ 137 StreamID: 0x1337, 138 Data: []byte("foobar"), 139 } 140 b, err := f.Append(nil, protocol.Version1) 141 Expect(err).ToNot(HaveOccurred()) 142 expected := []byte{0x8} 143 expected = append(expected, encodeVarInt(0x1337)...) // stream ID 144 expected = append(expected, []byte("foobar")...) 145 Expect(b).To(Equal(expected)) 146 }) 147 148 It("writes a frame with offset", func() { 149 f := &StreamFrame{ 150 StreamID: 0x1337, 151 Offset: 0x123456, 152 Data: []byte("foobar"), 153 } 154 b, err := f.Append(nil, protocol.Version1) 155 Expect(err).ToNot(HaveOccurred()) 156 expected := []byte{0x8 ^ 0x4} 157 expected = append(expected, encodeVarInt(0x1337)...) // stream ID 158 expected = append(expected, encodeVarInt(0x123456)...) // offset 159 expected = append(expected, []byte("foobar")...) 160 Expect(b).To(Equal(expected)) 161 }) 162 163 It("writes a frame with FIN bit", func() { 164 f := &StreamFrame{ 165 StreamID: 0x1337, 166 Offset: 0x123456, 167 Fin: true, 168 } 169 b, err := f.Append(nil, protocol.Version1) 170 Expect(err).ToNot(HaveOccurred()) 171 expected := []byte{0x8 ^ 0x4 ^ 0x1} 172 expected = append(expected, encodeVarInt(0x1337)...) // stream ID 173 expected = append(expected, encodeVarInt(0x123456)...) // offset 174 Expect(b).To(Equal(expected)) 175 }) 176 177 It("writes a frame with data length", func() { 178 f := &StreamFrame{ 179 StreamID: 0x1337, 180 Data: []byte("foobar"), 181 DataLenPresent: true, 182 } 183 b, err := f.Append(nil, protocol.Version1) 184 Expect(err).ToNot(HaveOccurred()) 185 expected := []byte{0x8 ^ 0x2} 186 expected = append(expected, encodeVarInt(0x1337)...) // stream ID 187 expected = append(expected, encodeVarInt(6)...) // data length 188 expected = append(expected, []byte("foobar")...) 189 Expect(b).To(Equal(expected)) 190 }) 191 192 It("writes a frame with data length and offset", func() { 193 f := &StreamFrame{ 194 StreamID: 0x1337, 195 Data: []byte("foobar"), 196 DataLenPresent: true, 197 Offset: 0x123456, 198 } 199 b, err := f.Append(nil, protocol.Version1) 200 Expect(err).ToNot(HaveOccurred()) 201 expected := []byte{0x8 ^ 0x4 ^ 0x2} 202 expected = append(expected, encodeVarInt(0x1337)...) // stream ID 203 expected = append(expected, encodeVarInt(0x123456)...) // offset 204 expected = append(expected, encodeVarInt(6)...) // data length 205 expected = append(expected, []byte("foobar")...) 206 Expect(b).To(Equal(expected)) 207 }) 208 209 It("refuses to write an empty frame without FIN", func() { 210 f := &StreamFrame{ 211 StreamID: 0x42, 212 Offset: 0x1337, 213 } 214 _, err := f.Append(nil, protocol.Version1) 215 Expect(err).To(MatchError("StreamFrame: attempting to write empty frame without FIN")) 216 }) 217 }) 218 219 Context("length", func() { 220 It("has the right length for a frame without offset and data length", func() { 221 f := &StreamFrame{ 222 StreamID: 0x1337, 223 Data: []byte("foobar"), 224 } 225 Expect(f.Length(protocol.Version1)).To(BeEquivalentTo(1 + quicvarint.Len(0x1337) + 6)) 226 }) 227 228 It("has the right length for a frame with offset", func() { 229 f := &StreamFrame{ 230 StreamID: 0x1337, 231 Offset: 0x42, 232 Data: []byte("foobar"), 233 } 234 Expect(f.Length(protocol.Version1)).To(BeEquivalentTo(1 + quicvarint.Len(0x1337) + quicvarint.Len(0x42) + 6)) 235 }) 236 237 It("has the right length for a frame with data length", func() { 238 f := &StreamFrame{ 239 StreamID: 0x1337, 240 Offset: 0x1234567, 241 DataLenPresent: true, 242 Data: []byte("foobar"), 243 } 244 Expect(f.Length(protocol.Version1)).To(BeEquivalentTo(1 + quicvarint.Len(0x1337) + quicvarint.Len(0x1234567) + quicvarint.Len(6) + 6)) 245 }) 246 }) 247 248 Context("max data length", func() { 249 const maxSize = 3000 250 251 It("always returns a data length such that the resulting frame has the right size, if data length is not present", func() { 252 data := make([]byte, maxSize) 253 f := &StreamFrame{ 254 StreamID: 0x1337, 255 Offset: 0xdeadbeef, 256 } 257 for i := 1; i < 3000; i++ { 258 f.Data = nil 259 maxDataLen := f.MaxDataLen(protocol.ByteCount(i), protocol.Version1) 260 if maxDataLen == 0 { // 0 means that no valid STREAM frame can be written 261 // check that writing a minimal size STREAM frame (i.e. with 1 byte data) is actually larger than the desired size 262 f.Data = []byte{0} 263 b, err := f.Append(nil, protocol.Version1) 264 Expect(err).ToNot(HaveOccurred()) 265 Expect(len(b)).To(BeNumerically(">", i)) 266 continue 267 } 268 f.Data = data[:int(maxDataLen)] 269 b, err := f.Append(nil, protocol.Version1) 270 Expect(err).ToNot(HaveOccurred()) 271 Expect(len(b)).To(Equal(i)) 272 } 273 }) 274 275 It("always returns a data length such that the resulting frame has the right size, if data length is present", func() { 276 data := make([]byte, maxSize) 277 f := &StreamFrame{ 278 StreamID: 0x1337, 279 Offset: 0xdeadbeef, 280 DataLenPresent: true, 281 } 282 var frameOneByteTooSmallCounter int 283 for i := 1; i < 3000; i++ { 284 f.Data = nil 285 maxDataLen := f.MaxDataLen(protocol.ByteCount(i), protocol.Version1) 286 if maxDataLen == 0 { // 0 means that no valid STREAM frame can be written 287 // check that writing a minimal size STREAM frame (i.e. with 1 byte data) is actually larger than the desired size 288 f.Data = []byte{0} 289 b, err := f.Append(nil, protocol.Version1) 290 Expect(err).ToNot(HaveOccurred()) 291 Expect(len(b)).To(BeNumerically(">", i)) 292 continue 293 } 294 f.Data = data[:int(maxDataLen)] 295 b, err := f.Append(nil, protocol.Version1) 296 Expect(err).ToNot(HaveOccurred()) 297 // There's *one* pathological case, where a data length of x can be encoded into 1 byte 298 // but a data lengths of x+1 needs 2 bytes 299 // In that case, it's impossible to create a STREAM frame of the desired size 300 if len(b) == i-1 { 301 frameOneByteTooSmallCounter++ 302 continue 303 } 304 Expect(len(b)).To(Equal(i)) 305 } 306 Expect(frameOneByteTooSmallCounter).To(Equal(1)) 307 }) 308 }) 309 310 Context("splitting", func() { 311 It("doesn't split if the frame is short enough", func() { 312 f := &StreamFrame{ 313 StreamID: 0x1337, 314 DataLenPresent: true, 315 Offset: 0xdeadbeef, 316 Data: make([]byte, 100), 317 } 318 frame, needsSplit := f.MaybeSplitOffFrame(f.Length(protocol.Version1), protocol.Version1) 319 Expect(needsSplit).To(BeFalse()) 320 Expect(frame).To(BeNil()) 321 Expect(f.DataLen()).To(BeEquivalentTo(100)) 322 frame, needsSplit = f.MaybeSplitOffFrame(f.Length(protocol.Version1)-1, protocol.Version1) 323 Expect(needsSplit).To(BeTrue()) 324 Expect(frame.DataLen()).To(BeEquivalentTo(99)) 325 f.PutBack() 326 }) 327 328 It("keeps the data len", func() { 329 f := &StreamFrame{ 330 StreamID: 0x1337, 331 DataLenPresent: true, 332 Data: make([]byte, 100), 333 } 334 frame, needsSplit := f.MaybeSplitOffFrame(66, protocol.Version1) 335 Expect(needsSplit).To(BeTrue()) 336 Expect(frame).ToNot(BeNil()) 337 Expect(f.DataLenPresent).To(BeTrue()) 338 Expect(frame.DataLenPresent).To(BeTrue()) 339 }) 340 341 It("adjusts the offset", func() { 342 f := &StreamFrame{ 343 StreamID: 0x1337, 344 Offset: 0x100, 345 Data: []byte("foobar"), 346 } 347 frame, needsSplit := f.MaybeSplitOffFrame(f.Length(protocol.Version1)-3, protocol.Version1) 348 Expect(needsSplit).To(BeTrue()) 349 Expect(frame).ToNot(BeNil()) 350 Expect(frame.Offset).To(Equal(protocol.ByteCount(0x100))) 351 Expect(frame.Data).To(Equal([]byte("foo"))) 352 Expect(f.Offset).To(Equal(protocol.ByteCount(0x100 + 3))) 353 Expect(f.Data).To(Equal([]byte("bar"))) 354 }) 355 356 It("preserves the FIN bit", func() { 357 f := &StreamFrame{ 358 StreamID: 0x1337, 359 Fin: true, 360 Offset: 0xdeadbeef, 361 Data: make([]byte, 100), 362 } 363 frame, needsSplit := f.MaybeSplitOffFrame(50, protocol.Version1) 364 Expect(needsSplit).To(BeTrue()) 365 Expect(frame).ToNot(BeNil()) 366 Expect(frame.Offset).To(BeNumerically("<", f.Offset)) 367 Expect(f.Fin).To(BeTrue()) 368 Expect(frame.Fin).To(BeFalse()) 369 }) 370 371 It("produces frames of the correct length, without data len", func() { 372 const size = 1000 373 f := &StreamFrame{ 374 StreamID: 0xdecafbad, 375 Offset: 0x1234, 376 Data: []byte{0}, 377 } 378 minFrameSize := f.Length(protocol.Version1) 379 for i := protocol.ByteCount(0); i < minFrameSize; i++ { 380 f, needsSplit := f.MaybeSplitOffFrame(i, protocol.Version1) 381 Expect(needsSplit).To(BeTrue()) 382 Expect(f).To(BeNil()) 383 } 384 for i := minFrameSize; i < size; i++ { 385 f.fromPool = false 386 f.Data = make([]byte, size) 387 f, needsSplit := f.MaybeSplitOffFrame(i, protocol.Version1) 388 Expect(needsSplit).To(BeTrue()) 389 Expect(f.Length(protocol.Version1)).To(Equal(i)) 390 } 391 }) 392 393 It("produces frames of the correct length, with data len", func() { 394 const size = 1000 395 f := &StreamFrame{ 396 StreamID: 0xdecafbad, 397 Offset: 0x1234, 398 DataLenPresent: true, 399 Data: []byte{0}, 400 } 401 minFrameSize := f.Length(protocol.Version1) 402 for i := protocol.ByteCount(0); i < minFrameSize; i++ { 403 f, needsSplit := f.MaybeSplitOffFrame(i, protocol.Version1) 404 Expect(needsSplit).To(BeTrue()) 405 Expect(f).To(BeNil()) 406 } 407 var frameOneByteTooSmallCounter int 408 for i := minFrameSize; i < size; i++ { 409 f.fromPool = false 410 f.Data = make([]byte, size) 411 newFrame, needsSplit := f.MaybeSplitOffFrame(i, protocol.Version1) 412 Expect(needsSplit).To(BeTrue()) 413 // There's *one* pathological case, where a data length of x can be encoded into 1 byte 414 // but a data lengths of x+1 needs 2 bytes 415 // In that case, it's impossible to create a STREAM frame of the desired size 416 if newFrame.Length(protocol.Version1) == i-1 { 417 frameOneByteTooSmallCounter++ 418 continue 419 } 420 Expect(newFrame.Length(protocol.Version1)).To(Equal(i)) 421 } 422 Expect(frameOneByteTooSmallCounter).To(Equal(1)) 423 }) 424 }) 425 })