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