diff --git a/session_test.go b/session_test.go index 0f876920..9f781521 100644 --- a/session_test.go +++ b/session_test.go @@ -347,6 +347,7 @@ var _ = Describe("Session", func() { StreamID: 5, ByteOffset: 0x1337, })) + Expect(str.(*stream).finished()).To(BeTrue()) }) It("doesn't queue a RST_STREAM for a stream that it already sent a FIN on", func() { @@ -358,6 +359,7 @@ var _ = Describe("Session", func() { }) Expect(err).ToNot(HaveOccurred()) Expect(session.packer.controlFrames).To(BeEmpty()) + Expect(str.(*stream).finished()).To(BeTrue()) }) It("passes the byte offset to the flow controller", func() { @@ -403,6 +405,7 @@ var _ = Describe("Session", func() { StreamID: 5, ByteOffset: 0x1337, })) + Expect(str.finished()).To(BeFalse()) }) It("doesn't queue another RST_STREAM, when it receives an RST_STREAM as a response for the first", func() { @@ -418,7 +421,6 @@ var _ = Describe("Session", func() { Expect(err).ToNot(HaveOccurred()) Expect(session.packer.controlFrames).To(HaveLen(1)) }) - }) Context("handling WINDOW_UPDATE frames", func() { diff --git a/stream.go b/stream.go index 6bf95782..0c4a8acc 100644 --- a/stream.go +++ b/stream.go @@ -310,7 +310,11 @@ func (s *stream) finishedWriteAndSentFin() bool { } func (s *stream) finished() bool { - return s.cancelled.Get() || (s.finishedReading.Get() && s.finishedWriteAndSentFin()) + return s.cancelled.Get() || + (s.finishedReading.Get() && s.finishedWriteAndSentFin()) || + (s.resetRemotely.Get() && s.rstSent.Get()) || + (s.finishedReading.Get() && s.rstSent.Get()) || + (s.finishedWriteAndSentFin() && s.resetRemotely.Get()) } func (s *stream) StreamID() protocol.StreamID { diff --git a/stream_test.go b/stream_test.go index fac305ef..d27ae12b 100644 --- a/stream_test.go +++ b/stream_test.go @@ -732,4 +732,60 @@ var _ = Describe("Stream", func() { }) }) + Context("closing", func() { + testErr := errors.New("testErr") + + finishReading := func() { + err := str.AddStreamFrame(&frames.StreamFrame{FinBit: true}) + Expect(err).ToNot(HaveOccurred()) + b := make([]byte, 100) + _, err = str.Read(b) + Expect(err).To(MatchError(io.EOF)) + } + + It("is finished after it is canceled", func() { + str.Cancel(testErr) + Expect(str.finished()).To(BeTrue()) + }) + + It("is not finished if it is only closed for writing", func() { + str.Close() + str.sentFin() + Expect(str.finished()).To(BeFalse()) + }) + + It("is not finished if it is only closed for reading", func() { + finishReading() + Expect(str.finished()).To(BeFalse()) + }) + + It("is finished after receiving a RST and sending one", func() { + // this directly sends a rst + str.RegisterRemoteError(testErr) + Expect(str.rstSent.Get()).To(BeTrue()) + Expect(str.finished()).To(BeTrue()) + }) + + It("is finished after being locally reset and receiving a RST in response", func() { + str.Reset(testErr) + Expect(str.finished()).To(BeFalse()) + str.RegisterRemoteError(testErr) + Expect(str.finished()).To(BeTrue()) + }) + + It("is finished after finishing writing and receiving a RST", func() { + str.Close() + str.sentFin() + str.RegisterRemoteError(testErr) + Expect(str.finished()).To(BeTrue()) + }) + + It("is finished after finishing reading and being locally reset", func() { + finishReading() + Expect(str.finished()).To(BeFalse()) + str.Reset(testErr) + Expect(str.finished()).To(BeTrue()) + }) + }) + })