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