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