github.com/MerlinKodo/quic-go@v0.39.2/framer_test.go (about) 1 package quic 2 3 import ( 4 "bytes" 5 "math/rand" 6 7 "github.com/MerlinKodo/quic-go/internal/ackhandler" 8 "github.com/MerlinKodo/quic-go/internal/protocol" 9 "github.com/MerlinKodo/quic-go/internal/wire" 10 11 . "github.com/onsi/ginkgo/v2" 12 . "github.com/onsi/gomega" 13 "go.uber.org/mock/gomock" 14 ) 15 16 var _ = Describe("Framer", func() { 17 const ( 18 id1 = protocol.StreamID(10) 19 id2 = protocol.StreamID(11) 20 ) 21 22 var ( 23 framer framer 24 stream1, stream2 *MockSendStreamI 25 streamGetter *MockStreamGetter 26 version protocol.VersionNumber 27 ) 28 29 BeforeEach(func() { 30 streamGetter = NewMockStreamGetter(mockCtrl) 31 stream1 = NewMockSendStreamI(mockCtrl) 32 stream1.EXPECT().StreamID().Return(protocol.StreamID(5)).AnyTimes() 33 stream2 = NewMockSendStreamI(mockCtrl) 34 stream2.EXPECT().StreamID().Return(protocol.StreamID(6)).AnyTimes() 35 framer = newFramer(streamGetter) 36 }) 37 38 Context("handling control frames", func() { 39 It("adds control frames", func() { 40 mdf := &wire.MaxDataFrame{MaximumData: 0x42} 41 msf := &wire.MaxStreamsFrame{MaxStreamNum: 0x1337} 42 framer.QueueControlFrame(mdf) 43 framer.QueueControlFrame(msf) 44 frames, length := framer.AppendControlFrames(nil, 1000, protocol.Version1) 45 Expect(frames).To(HaveLen(2)) 46 fs := []wire.Frame{frames[0].Frame, frames[1].Frame} 47 Expect(fs).To(ContainElement(mdf)) 48 Expect(fs).To(ContainElement(msf)) 49 Expect(length).To(Equal(mdf.Length(version) + msf.Length(version))) 50 }) 51 52 It("says if it has data", func() { 53 Expect(framer.HasData()).To(BeFalse()) 54 f := &wire.MaxDataFrame{MaximumData: 0x42} 55 framer.QueueControlFrame(f) 56 Expect(framer.HasData()).To(BeTrue()) 57 frames, _ := framer.AppendControlFrames(nil, 1000, protocol.Version1) 58 Expect(frames).To(HaveLen(1)) 59 Expect(framer.HasData()).To(BeFalse()) 60 }) 61 62 It("appends to the slice given", func() { 63 ping := &wire.PingFrame{} 64 mdf := &wire.MaxDataFrame{MaximumData: 0x42} 65 framer.QueueControlFrame(mdf) 66 frames, length := framer.AppendControlFrames([]ackhandler.Frame{{Frame: ping}}, 1000, protocol.Version1) 67 Expect(frames).To(HaveLen(2)) 68 Expect(frames[0].Frame).To(Equal(ping)) 69 Expect(frames[1].Frame).To(Equal(mdf)) 70 Expect(length).To(Equal(mdf.Length(version))) 71 }) 72 73 It("adds the right number of frames", func() { 74 maxSize := protocol.ByteCount(1000) 75 bf := &wire.DataBlockedFrame{MaximumData: 0x1337} 76 bfLen := bf.Length(version) 77 numFrames := int(maxSize / bfLen) // max number of frames that fit into maxSize 78 for i := 0; i < numFrames+1; i++ { 79 framer.QueueControlFrame(bf) 80 } 81 frames, length := framer.AppendControlFrames(nil, maxSize, protocol.Version1) 82 Expect(frames).To(HaveLen(numFrames)) 83 Expect(length).To(BeNumerically(">", maxSize-bfLen)) 84 frames, length = framer.AppendControlFrames(nil, maxSize, protocol.Version1) 85 Expect(frames).To(HaveLen(1)) 86 Expect(length).To(Equal(bfLen)) 87 }) 88 89 It("drops *_BLOCKED frames when 0-RTT is rejected", func() { 90 ping := &wire.PingFrame{} 91 ncid := &wire.NewConnectionIDFrame{ 92 SequenceNumber: 10, 93 ConnectionID: protocol.ParseConnectionID([]byte{0xde, 0xad, 0xbe, 0xef}), 94 } 95 frames := []wire.Frame{ 96 &wire.DataBlockedFrame{MaximumData: 1337}, 97 &wire.StreamDataBlockedFrame{StreamID: 42, MaximumStreamData: 1337}, 98 &wire.StreamsBlockedFrame{StreamLimit: 13}, 99 ping, 100 ncid, 101 } 102 rand.Shuffle(len(frames), func(i, j int) { frames[i], frames[j] = frames[j], frames[i] }) 103 for _, f := range frames { 104 framer.QueueControlFrame(f) 105 } 106 Expect(framer.Handle0RTTRejection()).To(Succeed()) 107 fs, length := framer.AppendControlFrames(nil, protocol.MaxByteCount, protocol.Version1) 108 Expect(fs).To(HaveLen(2)) 109 Expect(length).To(Equal(ping.Length(version) + ncid.Length(version))) 110 }) 111 }) 112 113 Context("popping STREAM frames", func() { 114 It("returns nil when popping an empty framer", func() { 115 Expect(framer.AppendStreamFrames(nil, 1000, protocol.Version1)).To(BeEmpty()) 116 }) 117 118 It("returns STREAM frames", func() { 119 streamGetter.EXPECT().GetOrOpenSendStream(id1).Return(stream1, nil) 120 f := &wire.StreamFrame{ 121 StreamID: id1, 122 Data: []byte("foobar"), 123 Offset: 42, 124 DataLenPresent: true, 125 } 126 stream1.EXPECT().popStreamFrame(gomock.Any(), protocol.Version1).Return(ackhandler.StreamFrame{Frame: f}, true, false) 127 framer.AddActiveStream(id1) 128 fs, length := framer.AppendStreamFrames(nil, 1000, protocol.Version1) 129 Expect(fs).To(HaveLen(1)) 130 Expect(fs[0].Frame.DataLenPresent).To(BeFalse()) 131 Expect(length).To(Equal(f.Length(version))) 132 }) 133 134 It("says if it has data", func() { 135 streamGetter.EXPECT().GetOrOpenSendStream(id1).Return(stream1, nil).Times(2) 136 Expect(framer.HasData()).To(BeFalse()) 137 framer.AddActiveStream(id1) 138 Expect(framer.HasData()).To(BeTrue()) 139 f1 := &wire.StreamFrame{StreamID: id1, Data: []byte("foo")} 140 f2 := &wire.StreamFrame{StreamID: id1, Data: []byte("bar")} 141 stream1.EXPECT().popStreamFrame(gomock.Any(), protocol.Version1).Return(ackhandler.StreamFrame{Frame: f1}, true, true) 142 stream1.EXPECT().popStreamFrame(gomock.Any(), protocol.Version1).Return(ackhandler.StreamFrame{Frame: f2}, true, false) 143 frames, _ := framer.AppendStreamFrames(nil, protocol.MaxByteCount, protocol.Version1) 144 Expect(frames).To(HaveLen(1)) 145 Expect(frames[0].Frame).To(Equal(f1)) 146 Expect(framer.HasData()).To(BeTrue()) 147 frames, _ = framer.AppendStreamFrames(nil, protocol.MaxByteCount, protocol.Version1) 148 Expect(frames).To(HaveLen(1)) 149 Expect(frames[0].Frame).To(Equal(f2)) 150 Expect(framer.HasData()).To(BeFalse()) 151 }) 152 153 It("appends to a frame slice", func() { 154 streamGetter.EXPECT().GetOrOpenSendStream(id1).Return(stream1, nil) 155 f := &wire.StreamFrame{ 156 StreamID: id1, 157 Data: []byte("foobar"), 158 DataLenPresent: true, 159 } 160 stream1.EXPECT().popStreamFrame(gomock.Any(), protocol.Version1).Return(ackhandler.StreamFrame{Frame: f}, true, false) 161 framer.AddActiveStream(id1) 162 f0 := ackhandler.StreamFrame{Frame: &wire.StreamFrame{StreamID: 9999}} 163 frames := []ackhandler.StreamFrame{f0} 164 fs, length := framer.AppendStreamFrames(frames, 1000, protocol.Version1) 165 Expect(fs).To(HaveLen(2)) 166 Expect(fs[0]).To(Equal(f0)) 167 Expect(fs[1].Frame.Data).To(Equal([]byte("foobar"))) 168 Expect(fs[1].Frame.DataLenPresent).To(BeFalse()) 169 Expect(length).To(Equal(f.Length(version))) 170 }) 171 172 It("skips a stream that was reported active, but was completed shortly after", func() { 173 streamGetter.EXPECT().GetOrOpenSendStream(id1).Return(nil, nil) 174 streamGetter.EXPECT().GetOrOpenSendStream(id2).Return(stream2, nil) 175 f := &wire.StreamFrame{ 176 StreamID: id2, 177 Data: []byte("foobar"), 178 DataLenPresent: true, 179 } 180 stream2.EXPECT().popStreamFrame(gomock.Any(), protocol.Version1).Return(ackhandler.StreamFrame{Frame: f}, true, false) 181 framer.AddActiveStream(id1) 182 framer.AddActiveStream(id2) 183 frames, _ := framer.AppendStreamFrames(nil, 1000, protocol.Version1) 184 Expect(frames).To(HaveLen(1)) 185 Expect(frames[0].Frame).To(Equal(f)) 186 }) 187 188 It("skips a stream that was reported active, but doesn't have any data", func() { 189 streamGetter.EXPECT().GetOrOpenSendStream(id1).Return(stream1, nil) 190 streamGetter.EXPECT().GetOrOpenSendStream(id2).Return(stream2, nil) 191 f := &wire.StreamFrame{ 192 StreamID: id2, 193 Data: []byte("foobar"), 194 DataLenPresent: true, 195 } 196 stream1.EXPECT().popStreamFrame(gomock.Any(), protocol.Version1).Return(ackhandler.StreamFrame{}, false, false) 197 stream2.EXPECT().popStreamFrame(gomock.Any(), protocol.Version1).Return(ackhandler.StreamFrame{Frame: f}, true, false) 198 framer.AddActiveStream(id1) 199 framer.AddActiveStream(id2) 200 frames, _ := framer.AppendStreamFrames(nil, 1000, protocol.Version1) 201 Expect(frames).To(HaveLen(1)) 202 Expect(frames[0].Frame).To(Equal(f)) 203 }) 204 205 It("pops from a stream multiple times, if it has enough data", func() { 206 streamGetter.EXPECT().GetOrOpenSendStream(id1).Return(stream1, nil).Times(2) 207 f1 := &wire.StreamFrame{StreamID: id1, Data: []byte("foobar")} 208 f2 := &wire.StreamFrame{StreamID: id1, Data: []byte("foobaz")} 209 stream1.EXPECT().popStreamFrame(gomock.Any(), protocol.Version1).Return(ackhandler.StreamFrame{Frame: f1}, true, true) 210 stream1.EXPECT().popStreamFrame(gomock.Any(), protocol.Version1).Return(ackhandler.StreamFrame{Frame: f2}, true, false) 211 framer.AddActiveStream(id1) // only add it once 212 frames, _ := framer.AppendStreamFrames(nil, protocol.MinStreamFrameSize, protocol.Version1) 213 Expect(frames).To(HaveLen(1)) 214 Expect(frames[0].Frame).To(Equal(f1)) 215 frames, _ = framer.AppendStreamFrames(nil, protocol.MinStreamFrameSize, protocol.Version1) 216 Expect(frames).To(HaveLen(1)) 217 Expect(frames[0].Frame).To(Equal(f2)) 218 // no further calls to popStreamFrame, after popStreamFrame said there's no more data 219 frames, _ = framer.AppendStreamFrames(nil, protocol.MinStreamFrameSize, protocol.Version1) 220 Expect(frames).To(BeNil()) 221 }) 222 223 It("re-queues a stream at the end, if it has enough data", func() { 224 streamGetter.EXPECT().GetOrOpenSendStream(id1).Return(stream1, nil).Times(2) 225 streamGetter.EXPECT().GetOrOpenSendStream(id2).Return(stream2, nil) 226 f11 := &wire.StreamFrame{StreamID: id1, Data: []byte("foobar")} 227 f12 := &wire.StreamFrame{StreamID: id1, Data: []byte("foobaz")} 228 f2 := &wire.StreamFrame{StreamID: id2, Data: []byte("raboof")} 229 stream1.EXPECT().popStreamFrame(gomock.Any(), protocol.Version1).Return(ackhandler.StreamFrame{Frame: f11}, true, true) 230 stream1.EXPECT().popStreamFrame(gomock.Any(), protocol.Version1).Return(ackhandler.StreamFrame{Frame: f12}, true, false) 231 stream2.EXPECT().popStreamFrame(gomock.Any(), protocol.Version1).Return(ackhandler.StreamFrame{Frame: f2}, true, false) 232 framer.AddActiveStream(id1) // only add it once 233 framer.AddActiveStream(id2) 234 // first a frame from stream 1 235 frames, _ := framer.AppendStreamFrames(nil, protocol.MinStreamFrameSize, protocol.Version1) 236 Expect(frames).To(HaveLen(1)) 237 Expect(frames[0].Frame).To(Equal(f11)) 238 // then a frame from stream 2 239 frames, _ = framer.AppendStreamFrames(nil, protocol.MinStreamFrameSize, protocol.Version1) 240 Expect(frames).To(HaveLen(1)) 241 Expect(frames[0].Frame).To(Equal(f2)) 242 // then another frame from stream 1 243 frames, _ = framer.AppendStreamFrames(nil, protocol.MinStreamFrameSize, protocol.Version1) 244 Expect(frames).To(HaveLen(1)) 245 Expect(frames[0].Frame).To(Equal(f12)) 246 }) 247 248 It("only dequeues data from each stream once per packet", func() { 249 streamGetter.EXPECT().GetOrOpenSendStream(id1).Return(stream1, nil) 250 streamGetter.EXPECT().GetOrOpenSendStream(id2).Return(stream2, nil) 251 f1 := &wire.StreamFrame{StreamID: id1, Data: []byte("foobar")} 252 f2 := &wire.StreamFrame{StreamID: id2, Data: []byte("raboof")} 253 // both streams have more data, and will be re-queued 254 stream1.EXPECT().popStreamFrame(gomock.Any(), protocol.Version1).Return(ackhandler.StreamFrame{Frame: f1}, true, true) 255 stream2.EXPECT().popStreamFrame(gomock.Any(), protocol.Version1).Return(ackhandler.StreamFrame{Frame: f2}, true, true) 256 framer.AddActiveStream(id1) 257 framer.AddActiveStream(id2) 258 frames, length := framer.AppendStreamFrames(nil, 1000, protocol.Version1) 259 Expect(frames).To(HaveLen(2)) 260 Expect(frames[0].Frame).To(Equal(f1)) 261 Expect(frames[1].Frame).To(Equal(f2)) 262 Expect(length).To(Equal(f1.Length(version) + f2.Length(version))) 263 }) 264 265 It("returns multiple normal frames in the order they were reported active", func() { 266 streamGetter.EXPECT().GetOrOpenSendStream(id1).Return(stream1, nil) 267 streamGetter.EXPECT().GetOrOpenSendStream(id2).Return(stream2, nil) 268 f1 := &wire.StreamFrame{Data: []byte("foobar")} 269 f2 := &wire.StreamFrame{Data: []byte("foobaz")} 270 stream1.EXPECT().popStreamFrame(gomock.Any(), protocol.Version1).Return(ackhandler.StreamFrame{Frame: f1}, true, false) 271 stream2.EXPECT().popStreamFrame(gomock.Any(), protocol.Version1).Return(ackhandler.StreamFrame{Frame: f2}, true, false) 272 framer.AddActiveStream(id2) 273 framer.AddActiveStream(id1) 274 frames, _ := framer.AppendStreamFrames(nil, 1000, protocol.Version1) 275 Expect(frames).To(HaveLen(2)) 276 Expect(frames[0].Frame).To(Equal(f2)) 277 Expect(frames[1].Frame).To(Equal(f1)) 278 }) 279 280 It("only asks a stream for data once, even if it was reported active multiple times", func() { 281 streamGetter.EXPECT().GetOrOpenSendStream(id1).Return(stream1, nil) 282 f := &wire.StreamFrame{Data: []byte("foobar")} 283 stream1.EXPECT().popStreamFrame(gomock.Any(), protocol.Version1).Return(ackhandler.StreamFrame{Frame: f}, true, false) // only one call to this function 284 framer.AddActiveStream(id1) 285 framer.AddActiveStream(id1) 286 frames, _ := framer.AppendStreamFrames(nil, 1000, protocol.Version1) 287 Expect(frames).To(HaveLen(1)) 288 }) 289 290 It("does not pop empty frames", func() { 291 fs, length := framer.AppendStreamFrames(nil, 500, protocol.Version1) 292 Expect(fs).To(BeEmpty()) 293 Expect(length).To(BeZero()) 294 }) 295 296 It("pops maximum size STREAM frames", func() { 297 for i := protocol.MinStreamFrameSize; i < 2000; i++ { 298 streamGetter.EXPECT().GetOrOpenSendStream(id1).Return(stream1, nil) 299 stream1.EXPECT().popStreamFrame(gomock.Any(), protocol.Version1).DoAndReturn(func(size protocol.ByteCount, v protocol.VersionNumber) (ackhandler.StreamFrame, bool, bool) { 300 f := &wire.StreamFrame{ 301 StreamID: id1, 302 DataLenPresent: true, 303 } 304 f.Data = make([]byte, f.MaxDataLen(size, v)) 305 Expect(f.Length(version)).To(Equal(size)) 306 return ackhandler.StreamFrame{Frame: f}, true, false 307 }) 308 framer.AddActiveStream(id1) 309 frames, _ := framer.AppendStreamFrames(nil, i, protocol.Version1) 310 Expect(frames).To(HaveLen(1)) 311 f := frames[0].Frame 312 Expect(f.DataLenPresent).To(BeFalse()) 313 Expect(f.Length(version)).To(Equal(i)) 314 } 315 }) 316 317 It("pops multiple STREAM frames", func() { 318 for i := 2 * protocol.MinStreamFrameSize; i < 2000; i++ { 319 streamGetter.EXPECT().GetOrOpenSendStream(id1).Return(stream1, nil) 320 streamGetter.EXPECT().GetOrOpenSendStream(id2).Return(stream2, nil) 321 stream1.EXPECT().popStreamFrame(gomock.Any(), protocol.Version1).DoAndReturn(func(size protocol.ByteCount, v protocol.VersionNumber) (ackhandler.StreamFrame, bool, bool) { 322 f := &wire.StreamFrame{ 323 StreamID: id2, 324 DataLenPresent: true, 325 } 326 f.Data = make([]byte, f.MaxDataLen(protocol.MinStreamFrameSize, v)) 327 return ackhandler.StreamFrame{Frame: f}, true, false 328 }) 329 stream2.EXPECT().popStreamFrame(gomock.Any(), protocol.Version1).DoAndReturn(func(size protocol.ByteCount, v protocol.VersionNumber) (ackhandler.StreamFrame, bool, bool) { 330 f := &wire.StreamFrame{ 331 StreamID: id2, 332 DataLenPresent: true, 333 } 334 f.Data = make([]byte, f.MaxDataLen(size, v)) 335 Expect(f.Length(version)).To(Equal(size)) 336 return ackhandler.StreamFrame{Frame: f}, true, false 337 }) 338 framer.AddActiveStream(id1) 339 framer.AddActiveStream(id2) 340 frames, _ := framer.AppendStreamFrames(nil, i, protocol.Version1) 341 Expect(frames).To(HaveLen(2)) 342 f1 := frames[0].Frame 343 f2 := frames[1].Frame 344 Expect(f1.DataLenPresent).To(BeTrue()) 345 Expect(f2.DataLenPresent).To(BeFalse()) 346 Expect(f1.Length(version) + f2.Length(version)).To(Equal(i)) 347 } 348 }) 349 350 It("pops frames that when asked for the the minimum STREAM frame size", func() { 351 streamGetter.EXPECT().GetOrOpenSendStream(id1).Return(stream1, nil) 352 f := &wire.StreamFrame{Data: []byte("foobar")} 353 stream1.EXPECT().popStreamFrame(gomock.Any(), protocol.Version1).Return(ackhandler.StreamFrame{Frame: f}, true, false) 354 framer.AddActiveStream(id1) 355 framer.AppendStreamFrames(nil, protocol.MinStreamFrameSize, protocol.Version1) 356 }) 357 358 It("does not pop frames smaller than the minimum size", func() { 359 // don't expect a call to PopStreamFrame() 360 framer.AppendStreamFrames(nil, protocol.MinStreamFrameSize-1, protocol.Version1) 361 }) 362 363 It("stops iterating when the remaining size is smaller than the minimum STREAM frame size", func() { 364 streamGetter.EXPECT().GetOrOpenSendStream(id1).Return(stream1, nil) 365 // pop a frame such that the remaining size is one byte less than the minimum STREAM frame size 366 f := &wire.StreamFrame{ 367 StreamID: id1, 368 Data: bytes.Repeat([]byte("f"), int(500-protocol.MinStreamFrameSize)), 369 DataLenPresent: true, 370 } 371 stream1.EXPECT().popStreamFrame(gomock.Any(), protocol.Version1).Return(ackhandler.StreamFrame{Frame: f}, true, false) 372 framer.AddActiveStream(id1) 373 fs, length := framer.AppendStreamFrames(nil, 500, protocol.Version1) 374 Expect(fs).To(HaveLen(1)) 375 Expect(fs[0].Frame).To(Equal(f)) 376 Expect(length).To(Equal(f.Length(version))) 377 }) 378 379 It("drops all STREAM frames when 0-RTT is rejected", func() { 380 framer.AddActiveStream(id1) 381 Expect(framer.Handle0RTTRejection()).To(Succeed()) 382 fs, length := framer.AppendStreamFrames(nil, protocol.MaxByteCount, protocol.Version1) 383 Expect(fs).To(BeEmpty()) 384 Expect(length).To(BeZero()) 385 }) 386 }) 387 })