github.com/apernet/quic-go@v0.43.1-0.20240515053213-5e9e635fd9f0/receive_stream_test.go (about)

     1  package quic
     2  
     3  import (
     4  	"errors"
     5  	"io"
     6  	"runtime"
     7  	"sync"
     8  	"sync/atomic"
     9  	"time"
    10  
    11  	"github.com/apernet/quic-go/internal/mocks"
    12  	"github.com/apernet/quic-go/internal/protocol"
    13  	"github.com/apernet/quic-go/internal/wire"
    14  
    15  	. "github.com/onsi/ginkgo/v2"
    16  	. "github.com/onsi/gomega"
    17  	"github.com/onsi/gomega/gbytes"
    18  	"go.uber.org/mock/gomock"
    19  )
    20  
    21  var _ = Describe("Receive Stream", func() {
    22  	const streamID protocol.StreamID = 1337
    23  
    24  	var (
    25  		str            *receiveStream
    26  		strWithTimeout io.Reader // str wrapped with gbytes.TimeoutReader
    27  		mockFC         *mocks.MockStreamFlowController
    28  		mockSender     *MockStreamSender
    29  	)
    30  
    31  	BeforeEach(func() {
    32  		mockSender = NewMockStreamSender(mockCtrl)
    33  		mockFC = mocks.NewMockStreamFlowController(mockCtrl)
    34  		str = newReceiveStream(streamID, mockSender, mockFC)
    35  
    36  		timeout := scaleDuration(250 * time.Millisecond)
    37  		strWithTimeout = gbytes.TimeoutReader(str, timeout)
    38  	})
    39  
    40  	It("gets stream id", func() {
    41  		Expect(str.StreamID()).To(Equal(protocol.StreamID(1337)))
    42  	})
    43  
    44  	Context("reading", func() {
    45  		It("reads a single STREAM frame", func() {
    46  			mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(4), false)
    47  			mockFC.EXPECT().AddBytesRead(protocol.ByteCount(4))
    48  			frame := wire.StreamFrame{
    49  				Offset: 0,
    50  				Data:   []byte{0xDE, 0xAD, 0xBE, 0xEF},
    51  			}
    52  			err := str.handleStreamFrame(&frame)
    53  			Expect(err).ToNot(HaveOccurred())
    54  			b := make([]byte, 4)
    55  			n, err := strWithTimeout.Read(b)
    56  			Expect(err).ToNot(HaveOccurred())
    57  			Expect(n).To(Equal(4))
    58  			Expect(b).To(Equal([]byte{0xDE, 0xAD, 0xBE, 0xEF}))
    59  		})
    60  
    61  		It("reads a single STREAM frame in multiple goes", func() {
    62  			mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(4), false)
    63  			mockFC.EXPECT().AddBytesRead(protocol.ByteCount(2))
    64  			mockFC.EXPECT().AddBytesRead(protocol.ByteCount(2))
    65  			frame := wire.StreamFrame{
    66  				Offset: 0,
    67  				Data:   []byte{0xDE, 0xAD, 0xBE, 0xEF},
    68  			}
    69  			err := str.handleStreamFrame(&frame)
    70  			Expect(err).ToNot(HaveOccurred())
    71  			b := make([]byte, 2)
    72  			n, err := strWithTimeout.Read(b)
    73  			Expect(err).ToNot(HaveOccurred())
    74  			Expect(n).To(Equal(2))
    75  			Expect(b).To(Equal([]byte{0xDE, 0xAD}))
    76  			n, err = strWithTimeout.Read(b)
    77  			Expect(err).ToNot(HaveOccurred())
    78  			Expect(n).To(Equal(2))
    79  			Expect(b).To(Equal([]byte{0xBE, 0xEF}))
    80  		})
    81  
    82  		It("reads all data available", func() {
    83  			mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(2), false)
    84  			mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(4), false)
    85  			mockFC.EXPECT().AddBytesRead(protocol.ByteCount(2)).Times(2)
    86  			frame1 := wire.StreamFrame{
    87  				Offset: 0,
    88  				Data:   []byte{0xDE, 0xAD},
    89  			}
    90  			frame2 := wire.StreamFrame{
    91  				Offset: 2,
    92  				Data:   []byte{0xBE, 0xEF},
    93  			}
    94  			err := str.handleStreamFrame(&frame1)
    95  			Expect(err).ToNot(HaveOccurred())
    96  			err = str.handleStreamFrame(&frame2)
    97  			Expect(err).ToNot(HaveOccurred())
    98  			b := make([]byte, 6)
    99  			n, err := strWithTimeout.Read(b)
   100  			Expect(err).ToNot(HaveOccurred())
   101  			Expect(n).To(Equal(4))
   102  			Expect(b).To(Equal([]byte{0xDE, 0xAD, 0xBE, 0xEF, 0x00, 0x00}))
   103  		})
   104  
   105  		It("assembles multiple STREAM frames", func() {
   106  			mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(2), false)
   107  			mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(4), false)
   108  			mockFC.EXPECT().AddBytesRead(protocol.ByteCount(2)).Times(2)
   109  			frame1 := wire.StreamFrame{
   110  				Offset: 0,
   111  				Data:   []byte{0xDE, 0xAD},
   112  			}
   113  			frame2 := wire.StreamFrame{
   114  				Offset: 2,
   115  				Data:   []byte{0xBE, 0xEF},
   116  			}
   117  			err := str.handleStreamFrame(&frame1)
   118  			Expect(err).ToNot(HaveOccurred())
   119  			err = str.handleStreamFrame(&frame2)
   120  			Expect(err).ToNot(HaveOccurred())
   121  			b := make([]byte, 4)
   122  			n, err := strWithTimeout.Read(b)
   123  			Expect(err).ToNot(HaveOccurred())
   124  			Expect(n).To(Equal(4))
   125  			Expect(b).To(Equal([]byte{0xDE, 0xAD, 0xBE, 0xEF}))
   126  		})
   127  
   128  		It("waits until data is available", func() {
   129  			mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(2), false)
   130  			mockFC.EXPECT().AddBytesRead(protocol.ByteCount(2))
   131  			go func() {
   132  				defer GinkgoRecover()
   133  				frame := wire.StreamFrame{Data: []byte{0xDE, 0xAD}}
   134  				time.Sleep(10 * time.Millisecond)
   135  				err := str.handleStreamFrame(&frame)
   136  				Expect(err).ToNot(HaveOccurred())
   137  			}()
   138  			b := make([]byte, 2)
   139  			n, err := strWithTimeout.Read(b)
   140  			Expect(err).ToNot(HaveOccurred())
   141  			Expect(n).To(Equal(2))
   142  		})
   143  
   144  		It("handles STREAM frames in wrong order", func() {
   145  			mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(2), false)
   146  			mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(4), false)
   147  			mockFC.EXPECT().AddBytesRead(protocol.ByteCount(2)).Times(2)
   148  			frame1 := wire.StreamFrame{
   149  				Offset: 2,
   150  				Data:   []byte{0xBE, 0xEF},
   151  			}
   152  			frame2 := wire.StreamFrame{
   153  				Offset: 0,
   154  				Data:   []byte{0xDE, 0xAD},
   155  			}
   156  			err := str.handleStreamFrame(&frame1)
   157  			Expect(err).ToNot(HaveOccurred())
   158  			err = str.handleStreamFrame(&frame2)
   159  			Expect(err).ToNot(HaveOccurred())
   160  			b := make([]byte, 4)
   161  			n, err := strWithTimeout.Read(b)
   162  			Expect(err).ToNot(HaveOccurred())
   163  			Expect(n).To(Equal(4))
   164  			Expect(b).To(Equal([]byte{0xDE, 0xAD, 0xBE, 0xEF}))
   165  		})
   166  
   167  		It("ignores duplicate STREAM frames", func() {
   168  			mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(2), false)
   169  			mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(2), false)
   170  			mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(4), false)
   171  			mockFC.EXPECT().AddBytesRead(protocol.ByteCount(2)).Times(2)
   172  			frame1 := wire.StreamFrame{
   173  				Offset: 0,
   174  				Data:   []byte{0xDE, 0xAD},
   175  			}
   176  			frame2 := wire.StreamFrame{
   177  				Offset: 0,
   178  				Data:   []byte{0x13, 0x37},
   179  			}
   180  			frame3 := wire.StreamFrame{
   181  				Offset: 2,
   182  				Data:   []byte{0xBE, 0xEF},
   183  			}
   184  			err := str.handleStreamFrame(&frame1)
   185  			Expect(err).ToNot(HaveOccurred())
   186  			err = str.handleStreamFrame(&frame2)
   187  			Expect(err).ToNot(HaveOccurred())
   188  			err = str.handleStreamFrame(&frame3)
   189  			Expect(err).ToNot(HaveOccurred())
   190  			b := make([]byte, 4)
   191  			n, err := strWithTimeout.Read(b)
   192  			Expect(err).ToNot(HaveOccurred())
   193  			Expect(n).To(Equal(4))
   194  			Expect(b).To(Equal([]byte{0xDE, 0xAD, 0xBE, 0xEF}))
   195  		})
   196  
   197  		It("doesn't rejects a STREAM frames with an overlapping data range", func() {
   198  			mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(4), false)
   199  			mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(6), false)
   200  			mockFC.EXPECT().AddBytesRead(protocol.ByteCount(2))
   201  			mockFC.EXPECT().AddBytesRead(protocol.ByteCount(4))
   202  			frame1 := wire.StreamFrame{
   203  				Offset: 0,
   204  				Data:   []byte("foob"),
   205  			}
   206  			frame2 := wire.StreamFrame{
   207  				Offset: 2,
   208  				Data:   []byte("obar"),
   209  			}
   210  			err := str.handleStreamFrame(&frame1)
   211  			Expect(err).ToNot(HaveOccurred())
   212  			err = str.handleStreamFrame(&frame2)
   213  			Expect(err).ToNot(HaveOccurred())
   214  			b := make([]byte, 6)
   215  			n, err := strWithTimeout.Read(b)
   216  			Expect(err).ToNot(HaveOccurred())
   217  			Expect(n).To(Equal(6))
   218  			Expect(b).To(Equal([]byte("foobar")))
   219  		})
   220  
   221  		Context("deadlines", func() {
   222  			It("the deadline error has the right net.Error properties", func() {
   223  				Expect(errDeadline.Timeout()).To(BeTrue())
   224  				Expect(errDeadline).To(MatchError("deadline exceeded"))
   225  			})
   226  
   227  			It("returns an error when Read is called after the deadline", func() {
   228  				mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(6), false).AnyTimes()
   229  				Expect(str.handleStreamFrame(&wire.StreamFrame{Data: []byte("foobar")})).To(Succeed())
   230  				str.SetReadDeadline(time.Now().Add(-time.Second))
   231  				b := make([]byte, 6)
   232  				n, err := strWithTimeout.Read(b)
   233  				Expect(err).To(MatchError(errDeadline))
   234  				Expect(n).To(BeZero())
   235  			})
   236  
   237  			It("unblocks when the deadline is changed to the past", func() {
   238  				str.SetReadDeadline(time.Now().Add(time.Hour))
   239  				done := make(chan struct{})
   240  				go func() {
   241  					defer GinkgoRecover()
   242  					_, err := str.Read(make([]byte, 6))
   243  					Expect(err).To(MatchError(errDeadline))
   244  					close(done)
   245  				}()
   246  				Consistently(done).ShouldNot(BeClosed())
   247  				str.SetReadDeadline(time.Now().Add(-time.Hour))
   248  				Eventually(done).Should(BeClosed())
   249  			})
   250  
   251  			It("unblocks after the deadline", func() {
   252  				deadline := time.Now().Add(scaleDuration(50 * time.Millisecond))
   253  				str.SetReadDeadline(deadline)
   254  				b := make([]byte, 6)
   255  				n, err := strWithTimeout.Read(b)
   256  				Expect(err).To(MatchError(errDeadline))
   257  				Expect(n).To(BeZero())
   258  				Expect(time.Now()).To(BeTemporally("~", deadline, scaleDuration(20*time.Millisecond)))
   259  			})
   260  
   261  			It("doesn't unblock if the deadline is changed before the first one expires", func() {
   262  				deadline1 := time.Now().Add(scaleDuration(50 * time.Millisecond))
   263  				deadline2 := time.Now().Add(scaleDuration(100 * time.Millisecond))
   264  				str.SetReadDeadline(deadline1)
   265  				go func() {
   266  					defer GinkgoRecover()
   267  					time.Sleep(scaleDuration(20 * time.Millisecond))
   268  					str.SetReadDeadline(deadline2)
   269  					// make sure that this was actually execute before the deadline expires
   270  					Expect(time.Now()).To(BeTemporally("<", deadline1))
   271  				}()
   272  				runtime.Gosched()
   273  				b := make([]byte, 10)
   274  				n, err := strWithTimeout.Read(b)
   275  				Expect(err).To(MatchError(errDeadline))
   276  				Expect(n).To(BeZero())
   277  				Expect(time.Now()).To(BeTemporally("~", deadline2, scaleDuration(20*time.Millisecond)))
   278  			})
   279  
   280  			It("unblocks earlier, when a new deadline is set", func() {
   281  				deadline1 := time.Now().Add(scaleDuration(200 * time.Millisecond))
   282  				deadline2 := time.Now().Add(scaleDuration(50 * time.Millisecond))
   283  				go func() {
   284  					defer GinkgoRecover()
   285  					time.Sleep(scaleDuration(10 * time.Millisecond))
   286  					str.SetReadDeadline(deadline2)
   287  					// make sure that this was actually execute before the deadline expires
   288  					Expect(time.Now()).To(BeTemporally("<", deadline2))
   289  				}()
   290  				str.SetReadDeadline(deadline1)
   291  				runtime.Gosched()
   292  				b := make([]byte, 10)
   293  				_, err := strWithTimeout.Read(b)
   294  				Expect(err).To(MatchError(errDeadline))
   295  				Expect(time.Now()).To(BeTemporally("~", deadline2, scaleDuration(25*time.Millisecond)))
   296  			})
   297  
   298  			It("doesn't unblock if the deadline is removed", func() {
   299  				deadline := time.Now().Add(scaleDuration(50 * time.Millisecond))
   300  				str.SetReadDeadline(deadline)
   301  				deadlineUnset := make(chan struct{})
   302  				go func() {
   303  					defer GinkgoRecover()
   304  					time.Sleep(scaleDuration(20 * time.Millisecond))
   305  					str.SetReadDeadline(time.Time{})
   306  					// make sure that this was actually execute before the deadline expires
   307  					Expect(time.Now()).To(BeTemporally("<", deadline))
   308  					close(deadlineUnset)
   309  				}()
   310  				done := make(chan struct{})
   311  				go func() {
   312  					defer GinkgoRecover()
   313  					_, err := strWithTimeout.Read(make([]byte, 1))
   314  					Expect(err).To(MatchError("test done"))
   315  					close(done)
   316  				}()
   317  				runtime.Gosched()
   318  				Eventually(deadlineUnset).Should(BeClosed())
   319  				Consistently(done, scaleDuration(100*time.Millisecond)).ShouldNot(BeClosed())
   320  				// make the go routine return
   321  				str.closeForShutdown(errors.New("test done"))
   322  				Eventually(done).Should(BeClosed())
   323  			})
   324  		})
   325  
   326  		Context("closing", func() {
   327  			Context("with FIN bit", func() {
   328  				It("returns EOFs", func() {
   329  					mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(4), true)
   330  					mockFC.EXPECT().AddBytesRead(protocol.ByteCount(4))
   331  					str.handleStreamFrame(&wire.StreamFrame{
   332  						Offset: 0,
   333  						Data:   []byte{0xDE, 0xAD, 0xBE, 0xEF},
   334  						Fin:    true,
   335  					})
   336  					mockSender.EXPECT().onStreamCompleted(streamID)
   337  					b := make([]byte, 4)
   338  					n, err := strWithTimeout.Read(b)
   339  					Expect(err).To(MatchError(io.EOF))
   340  					Expect(n).To(Equal(4))
   341  					Expect(b).To(Equal([]byte{0xDE, 0xAD, 0xBE, 0xEF}))
   342  					n, err = strWithTimeout.Read(b)
   343  					Expect(n).To(BeZero())
   344  					Expect(err).To(MatchError(io.EOF))
   345  				})
   346  
   347  				It("handles out-of-order frames", func() {
   348  					mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(2), false)
   349  					mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(4), true)
   350  					mockFC.EXPECT().AddBytesRead(protocol.ByteCount(2)).Times(2)
   351  					frame1 := wire.StreamFrame{
   352  						Offset: 2,
   353  						Data:   []byte{0xBE, 0xEF},
   354  						Fin:    true,
   355  					}
   356  					frame2 := wire.StreamFrame{
   357  						Offset: 0,
   358  						Data:   []byte{0xDE, 0xAD},
   359  					}
   360  					err := str.handleStreamFrame(&frame1)
   361  					Expect(err).ToNot(HaveOccurred())
   362  					err = str.handleStreamFrame(&frame2)
   363  					Expect(err).ToNot(HaveOccurred())
   364  					mockSender.EXPECT().onStreamCompleted(streamID)
   365  					b := make([]byte, 4)
   366  					n, err := strWithTimeout.Read(b)
   367  					Expect(err).To(MatchError(io.EOF))
   368  					Expect(n).To(Equal(4))
   369  					Expect(b).To(Equal([]byte{0xDE, 0xAD, 0xBE, 0xEF}))
   370  					n, err = strWithTimeout.Read(b)
   371  					Expect(n).To(BeZero())
   372  					Expect(err).To(MatchError(io.EOF))
   373  				})
   374  
   375  				It("returns EOFs with partial read", func() {
   376  					mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(2), true)
   377  					mockFC.EXPECT().AddBytesRead(protocol.ByteCount(2))
   378  					err := str.handleStreamFrame(&wire.StreamFrame{
   379  						Offset: 0,
   380  						Data:   []byte{0xde, 0xad},
   381  						Fin:    true,
   382  					})
   383  					Expect(err).ToNot(HaveOccurred())
   384  					mockSender.EXPECT().onStreamCompleted(streamID)
   385  					b := make([]byte, 4)
   386  					n, err := strWithTimeout.Read(b)
   387  					Expect(err).To(MatchError(io.EOF))
   388  					Expect(n).To(Equal(2))
   389  					Expect(b[:n]).To(Equal([]byte{0xde, 0xad}))
   390  				})
   391  
   392  				It("handles immediate FINs", func() {
   393  					mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(0), true)
   394  					mockFC.EXPECT().AddBytesRead(protocol.ByteCount(0))
   395  					err := str.handleStreamFrame(&wire.StreamFrame{
   396  						Offset: 0,
   397  						Fin:    true,
   398  					})
   399  					Expect(err).ToNot(HaveOccurred())
   400  					mockSender.EXPECT().onStreamCompleted(streamID)
   401  					b := make([]byte, 4)
   402  					n, err := strWithTimeout.Read(b)
   403  					Expect(n).To(BeZero())
   404  					Expect(err).To(MatchError(io.EOF))
   405  				})
   406  
   407  				// Calling Read concurrently doesn't make any sense (and is forbidden),
   408  				// but we still want to make sure that we don't complete the stream more than once
   409  				// if the user misuses our API.
   410  				// This would lead to an INTERNAL_ERROR ("tried to delete unknown outgoing stream"),
   411  				// which can be hard to debug.
   412  				// Note that even without the protection built into the receiveStream, this test
   413  				// is very timing-dependent, and would need to run a few hundred times to trigger the failure.
   414  				It("handles concurrent reads", func() {
   415  					mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(6), gomock.Any()).AnyTimes()
   416  					var bytesRead protocol.ByteCount
   417  					mockFC.EXPECT().AddBytesRead(gomock.Any()).Do(func(n protocol.ByteCount) { bytesRead += n }).AnyTimes()
   418  
   419  					var numCompleted int32
   420  					mockSender.EXPECT().onStreamCompleted(streamID).Do(func(protocol.StreamID) {
   421  						atomic.AddInt32(&numCompleted, 1)
   422  					}).AnyTimes()
   423  					const num = 3
   424  					var wg sync.WaitGroup
   425  					wg.Add(num)
   426  					for i := 0; i < num; i++ {
   427  						go func() {
   428  							defer wg.Done()
   429  							defer GinkgoRecover()
   430  							_, err := str.Read(make([]byte, 8))
   431  							Expect(err).To(MatchError(io.EOF))
   432  						}()
   433  					}
   434  					str.handleStreamFrame(&wire.StreamFrame{
   435  						Offset: 0,
   436  						Data:   []byte("foobar"),
   437  						Fin:    true,
   438  					})
   439  					wg.Wait()
   440  					Expect(bytesRead).To(BeEquivalentTo(6))
   441  					Expect(atomic.LoadInt32(&numCompleted)).To(BeEquivalentTo(1))
   442  				})
   443  			})
   444  		})
   445  
   446  		Context("closing for shutdown", func() {
   447  			testErr := errors.New("test error")
   448  
   449  			It("immediately returns all reads", func() {
   450  				done := make(chan struct{})
   451  				b := make([]byte, 4)
   452  				go func() {
   453  					defer GinkgoRecover()
   454  					n, err := strWithTimeout.Read(b)
   455  					Expect(n).To(BeZero())
   456  					Expect(err).To(MatchError(testErr))
   457  					close(done)
   458  				}()
   459  				Consistently(done).ShouldNot(BeClosed())
   460  				str.closeForShutdown(testErr)
   461  				Eventually(done).Should(BeClosed())
   462  			})
   463  
   464  			It("errors for all following reads", func() {
   465  				str.closeForShutdown(testErr)
   466  				b := make([]byte, 1)
   467  				n, err := strWithTimeout.Read(b)
   468  				Expect(n).To(BeZero())
   469  				Expect(err).To(MatchError(testErr))
   470  			})
   471  		})
   472  	})
   473  
   474  	Context("stream cancellations", func() {
   475  		Context("canceling read", func() {
   476  			It("unblocks Read", func() {
   477  				mockSender.EXPECT().queueControlFrame(gomock.Any())
   478  				done := make(chan struct{})
   479  				go func() {
   480  					defer GinkgoRecover()
   481  					_, err := strWithTimeout.Read([]byte{0})
   482  					Expect(err).To(Equal(&StreamError{
   483  						StreamID:  streamID,
   484  						ErrorCode: 1234,
   485  						Remote:    false,
   486  					}))
   487  					close(done)
   488  				}()
   489  				Consistently(done).ShouldNot(BeClosed())
   490  				str.CancelRead(1234)
   491  				Eventually(done).Should(BeClosed())
   492  			})
   493  
   494  			It("doesn't allow further calls to Read", func() {
   495  				mockSender.EXPECT().queueControlFrame(gomock.Any())
   496  				str.CancelRead(1234)
   497  				_, err := strWithTimeout.Read([]byte{0})
   498  				Expect(err).To(Equal(&StreamError{
   499  					StreamID:  streamID,
   500  					ErrorCode: 1234,
   501  					Remote:    false,
   502  				}))
   503  			})
   504  
   505  			It("does nothing when CancelRead is called twice", func() {
   506  				mockSender.EXPECT().queueControlFrame(gomock.Any())
   507  				str.CancelRead(1234)
   508  				str.CancelRead(1234)
   509  				_, err := strWithTimeout.Read([]byte{0})
   510  				Expect(err).To(Equal(&StreamError{
   511  					StreamID:  streamID,
   512  					ErrorCode: 1234,
   513  					Remote:    false,
   514  				}))
   515  			})
   516  
   517  			It("queues a STOP_SENDING frame", func() {
   518  				mockSender.EXPECT().queueControlFrame(&wire.StopSendingFrame{
   519  					StreamID:  streamID,
   520  					ErrorCode: 1234,
   521  				})
   522  				str.CancelRead(1234)
   523  			})
   524  
   525  			It("doesn't send a STOP_SENDING frame, if the FIN was already read", func() {
   526  				mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(6), true)
   527  				mockFC.EXPECT().AddBytesRead(protocol.ByteCount(6))
   528  				// no calls to mockSender.queueControlFrame
   529  				Expect(str.handleStreamFrame(&wire.StreamFrame{
   530  					StreamID: streamID,
   531  					Data:     []byte("foobar"),
   532  					Fin:      true,
   533  				})).To(Succeed())
   534  				mockSender.EXPECT().onStreamCompleted(streamID)
   535  				n, err := strWithTimeout.Read(make([]byte, 100))
   536  				Expect(err).To(MatchError(io.EOF))
   537  				Expect(n).To(Equal(6))
   538  				str.CancelRead(1234)
   539  			})
   540  
   541  			It("doesn't send a STOP_SENDING frame, if the stream was already reset", func() {
   542  				mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(42), true)
   543  				mockFC.EXPECT().Abandon().MinTimes(1)
   544  				Expect(str.handleResetStreamFrame(&wire.ResetStreamFrame{
   545  					ErrorCode: 1337,
   546  					StreamID:  streamID,
   547  					FinalSize: 42,
   548  				})).To(Succeed())
   549  				mockSender.EXPECT().onStreamCompleted(gomock.Any())
   550  				str.CancelRead(1234)
   551  				// check that the error indicates a remote reset
   552  				n, err := str.Read([]byte{0})
   553  				Expect(err).To(HaveOccurred())
   554  				Expect(n).To(BeZero())
   555  				var streamErr *StreamError
   556  				Expect(errors.As(err, &streamErr)).To(BeTrue())
   557  				Expect(streamErr.ErrorCode).To(BeEquivalentTo(1337))
   558  				Expect(streamErr.Remote).To(BeTrue())
   559  			})
   560  
   561  			It("sends a STOP_SENDING after receiving the final offset", func() {
   562  				mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(6), true)
   563  				Expect(str.handleStreamFrame(&wire.StreamFrame{
   564  					Data: []byte("foobar"),
   565  					Fin:  true,
   566  				})).To(Succeed())
   567  				mockFC.EXPECT().Abandon()
   568  				mockSender.EXPECT().queueControlFrame(gomock.Any())
   569  				mockSender.EXPECT().onStreamCompleted(streamID)
   570  				str.CancelRead(1234)
   571  				// read the error
   572  				n, err := str.Read([]byte{0})
   573  				Expect(err).To(HaveOccurred())
   574  				Expect(n).To(BeZero())
   575  			})
   576  
   577  			It("completes the stream when receiving the Fin after the stream was canceled", func() {
   578  				mockSender.EXPECT().queueControlFrame(gomock.Any())
   579  				str.CancelRead(1234)
   580  				gomock.InOrder(
   581  					mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(1000), true),
   582  					mockFC.EXPECT().Abandon(),
   583  				)
   584  				mockSender.EXPECT().onStreamCompleted(streamID)
   585  				Expect(str.handleStreamFrame(&wire.StreamFrame{
   586  					Offset: 1000,
   587  					Fin:    true,
   588  				})).To(Succeed())
   589  			})
   590  
   591  			It("handles duplicate FinBits after the stream was canceled", func() {
   592  				mockSender.EXPECT().queueControlFrame(gomock.Any())
   593  				str.CancelRead(1234)
   594  				gomock.InOrder(
   595  					mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(1000), true),
   596  					mockFC.EXPECT().Abandon(),
   597  					mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(1000), true),
   598  				)
   599  				mockSender.EXPECT().onStreamCompleted(streamID)
   600  				Expect(str.handleStreamFrame(&wire.StreamFrame{
   601  					Offset: 1000,
   602  					Fin:    true,
   603  				})).To(Succeed())
   604  				Expect(str.handleStreamFrame(&wire.StreamFrame{
   605  					Offset: 1000,
   606  					Fin:    true,
   607  				})).To(Succeed())
   608  			})
   609  		})
   610  
   611  		Context("receiving RESET_STREAM frames", func() {
   612  			rst := &wire.ResetStreamFrame{
   613  				StreamID:  streamID,
   614  				FinalSize: 42,
   615  				ErrorCode: 1234,
   616  			}
   617  
   618  			It("unblocks Read", func() {
   619  				done := make(chan struct{})
   620  				go func() {
   621  					defer GinkgoRecover()
   622  					_, err := strWithTimeout.Read([]byte{0})
   623  					Expect(err).To(Equal(&StreamError{
   624  						StreamID:  streamID,
   625  						ErrorCode: 1234,
   626  						Remote:    true,
   627  					}))
   628  					close(done)
   629  				}()
   630  				Consistently(done).ShouldNot(BeClosed())
   631  				mockSender.EXPECT().onStreamCompleted(streamID)
   632  				gomock.InOrder(
   633  					mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(42), true),
   634  					mockFC.EXPECT().Abandon(),
   635  				)
   636  				Expect(str.handleResetStreamFrame(rst)).To(Succeed())
   637  				Eventually(done).Should(BeClosed())
   638  			})
   639  
   640  			It("doesn't allow further calls to Read", func() {
   641  				mockSender.EXPECT().onStreamCompleted(streamID)
   642  				gomock.InOrder(
   643  					mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(42), true),
   644  					mockFC.EXPECT().Abandon(),
   645  				)
   646  				Expect(str.handleResetStreamFrame(rst)).To(Succeed())
   647  				_, err := strWithTimeout.Read([]byte{0})
   648  				Expect(err).To(MatchError(&StreamError{
   649  					StreamID:  streamID,
   650  					ErrorCode: 1234,
   651  				}))
   652  			})
   653  
   654  			It("errors when receiving a RESET_STREAM with an inconsistent offset", func() {
   655  				testErr := errors.New("already received a different final offset before")
   656  				mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(42), true).Return(testErr)
   657  				err := str.handleResetStreamFrame(rst)
   658  				Expect(err).To(MatchError(testErr))
   659  			})
   660  
   661  			It("ignores duplicate RESET_STREAM frames", func() {
   662  				mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(42), true).Times(2)
   663  				mockFC.EXPECT().Abandon()
   664  				Expect(str.handleResetStreamFrame(rst)).To(Succeed())
   665  				Expect(str.handleResetStreamFrame(rst)).To(Succeed())
   666  			})
   667  
   668  			It("doesn't call onStreamCompleted again when the final offset was already received via Fin", func() {
   669  				mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(42), true).Times(2)
   670  				Expect(str.handleStreamFrame(&wire.StreamFrame{
   671  					StreamID: streamID,
   672  					Offset:   rst.FinalSize,
   673  					Fin:      true,
   674  				})).To(Succeed())
   675  				mockFC.EXPECT().Abandon().MinTimes(1)
   676  				mockSender.EXPECT().onStreamCompleted(streamID)
   677  				Expect(str.handleResetStreamFrame(rst)).To(Succeed())
   678  				// now read the error
   679  				n, err := str.Read([]byte{0})
   680  				Expect(err).To(HaveOccurred())
   681  				Expect(n).To(BeZero())
   682  			})
   683  
   684  			It("doesn't do anything when it was closed for shutdown", func() {
   685  				str.closeForShutdown(errors.New("shutdown"))
   686  				err := str.handleResetStreamFrame(rst)
   687  				Expect(err).ToNot(HaveOccurred())
   688  			})
   689  
   690  			It("handles RESET_STREAM after CancelRead", func() {
   691  				mockFC.EXPECT().Abandon()
   692  				mockSender.EXPECT().queueControlFrame(gomock.Any())
   693  				str.CancelRead(1234)
   694  				mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(42), true)
   695  				mockSender.EXPECT().onStreamCompleted(streamID)
   696  				Expect(str.handleResetStreamFrame(rst)).To(Succeed())
   697  				// check that the error indicates a local reset
   698  				n, err := str.Read([]byte{0})
   699  				Expect(err).To(HaveOccurred())
   700  				Expect(n).To(BeZero())
   701  				var streamErr *StreamError
   702  				Expect(errors.As(err, &streamErr)).To(BeTrue())
   703  				Expect(streamErr.Remote).To(BeFalse())
   704  			})
   705  		})
   706  	})
   707  
   708  	Context("flow control", func() {
   709  		It("errors when a STREAM frame causes a flow control violation", func() {
   710  			testErr := errors.New("flow control violation")
   711  			mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(8), false).Return(testErr)
   712  			frame := wire.StreamFrame{
   713  				Offset: 2,
   714  				Data:   []byte("foobar"),
   715  			}
   716  			err := str.handleStreamFrame(&frame)
   717  			Expect(err).To(MatchError(testErr))
   718  		})
   719  
   720  		It("gets a window update", func() {
   721  			mockFC.EXPECT().GetWindowUpdate().Return(protocol.ByteCount(0x100))
   722  			Expect(str.getWindowUpdate()).To(Equal(protocol.ByteCount(0x100)))
   723  		})
   724  	})
   725  })