github.com/daeuniverse/quic-go@v0.0.0-20240413031024-943f218e0810/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/daeuniverse/quic-go/internal/mocks" 12 "github.com/daeuniverse/quic-go/internal/protocol" 13 "github.com/daeuniverse/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 f := &wire.StreamFrame{Data: []byte("foobar")} 230 err := str.handleStreamFrame(f) 231 Expect(err).ToNot(HaveOccurred()) 232 str.SetReadDeadline(time.Now().Add(-time.Second)) 233 b := make([]byte, 6) 234 n, err := strWithTimeout.Read(b) 235 Expect(err).To(MatchError(errDeadline)) 236 Expect(n).To(BeZero()) 237 }) 238 239 It("unblocks when the deadline is changed to the past", func() { 240 str.SetReadDeadline(time.Now().Add(time.Hour)) 241 done := make(chan struct{}) 242 go func() { 243 defer GinkgoRecover() 244 _, err := str.Read(make([]byte, 6)) 245 Expect(err).To(MatchError(errDeadline)) 246 close(done) 247 }() 248 Consistently(done).ShouldNot(BeClosed()) 249 str.SetReadDeadline(time.Now().Add(-time.Hour)) 250 Eventually(done).Should(BeClosed()) 251 }) 252 253 It("unblocks after the deadline", func() { 254 deadline := time.Now().Add(scaleDuration(50 * time.Millisecond)) 255 str.SetReadDeadline(deadline) 256 b := make([]byte, 6) 257 n, err := strWithTimeout.Read(b) 258 Expect(err).To(MatchError(errDeadline)) 259 Expect(n).To(BeZero()) 260 Expect(time.Now()).To(BeTemporally("~", deadline, scaleDuration(20*time.Millisecond))) 261 }) 262 263 It("doesn't unblock if the deadline is changed before the first one expires", func() { 264 deadline1 := time.Now().Add(scaleDuration(50 * time.Millisecond)) 265 deadline2 := time.Now().Add(scaleDuration(100 * time.Millisecond)) 266 str.SetReadDeadline(deadline1) 267 go func() { 268 defer GinkgoRecover() 269 time.Sleep(scaleDuration(20 * time.Millisecond)) 270 str.SetReadDeadline(deadline2) 271 // make sure that this was actually execute before the deadline expires 272 Expect(time.Now()).To(BeTemporally("<", deadline1)) 273 }() 274 runtime.Gosched() 275 b := make([]byte, 10) 276 n, err := strWithTimeout.Read(b) 277 Expect(err).To(MatchError(errDeadline)) 278 Expect(n).To(BeZero()) 279 Expect(time.Now()).To(BeTemporally("~", deadline2, scaleDuration(20*time.Millisecond))) 280 }) 281 282 It("unblocks earlier, when a new deadline is set", func() { 283 deadline1 := time.Now().Add(scaleDuration(200 * time.Millisecond)) 284 deadline2 := time.Now().Add(scaleDuration(50 * time.Millisecond)) 285 go func() { 286 defer GinkgoRecover() 287 time.Sleep(scaleDuration(10 * time.Millisecond)) 288 str.SetReadDeadline(deadline2) 289 // make sure that this was actually execute before the deadline expires 290 Expect(time.Now()).To(BeTemporally("<", deadline2)) 291 }() 292 str.SetReadDeadline(deadline1) 293 runtime.Gosched() 294 b := make([]byte, 10) 295 _, err := strWithTimeout.Read(b) 296 Expect(err).To(MatchError(errDeadline)) 297 Expect(time.Now()).To(BeTemporally("~", deadline2, scaleDuration(25*time.Millisecond))) 298 }) 299 300 It("doesn't unblock if the deadline is removed", func() { 301 deadline := time.Now().Add(scaleDuration(50 * time.Millisecond)) 302 str.SetReadDeadline(deadline) 303 deadlineUnset := make(chan struct{}) 304 go func() { 305 defer GinkgoRecover() 306 time.Sleep(scaleDuration(20 * time.Millisecond)) 307 str.SetReadDeadline(time.Time{}) 308 // make sure that this was actually execute before the deadline expires 309 Expect(time.Now()).To(BeTemporally("<", deadline)) 310 close(deadlineUnset) 311 }() 312 done := make(chan struct{}) 313 go func() { 314 defer GinkgoRecover() 315 _, err := strWithTimeout.Read(make([]byte, 1)) 316 Expect(err).To(MatchError("test done")) 317 close(done) 318 }() 319 runtime.Gosched() 320 Eventually(deadlineUnset).Should(BeClosed()) 321 Consistently(done, scaleDuration(100*time.Millisecond)).ShouldNot(BeClosed()) 322 // make the go routine return 323 str.closeForShutdown(errors.New("test done")) 324 Eventually(done).Should(BeClosed()) 325 }) 326 }) 327 328 Context("closing", func() { 329 Context("with FIN bit", func() { 330 It("returns EOFs", func() { 331 mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(4), true) 332 mockFC.EXPECT().AddBytesRead(protocol.ByteCount(4)) 333 str.handleStreamFrame(&wire.StreamFrame{ 334 Offset: 0, 335 Data: []byte{0xDE, 0xAD, 0xBE, 0xEF}, 336 Fin: true, 337 }) 338 mockSender.EXPECT().onStreamCompleted(streamID) 339 b := make([]byte, 4) 340 n, err := strWithTimeout.Read(b) 341 Expect(err).To(MatchError(io.EOF)) 342 Expect(n).To(Equal(4)) 343 Expect(b).To(Equal([]byte{0xDE, 0xAD, 0xBE, 0xEF})) 344 n, err = strWithTimeout.Read(b) 345 Expect(n).To(BeZero()) 346 Expect(err).To(MatchError(io.EOF)) 347 }) 348 349 It("handles out-of-order frames", func() { 350 mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(2), false) 351 mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(4), true) 352 mockFC.EXPECT().AddBytesRead(protocol.ByteCount(2)).Times(2) 353 frame1 := wire.StreamFrame{ 354 Offset: 2, 355 Data: []byte{0xBE, 0xEF}, 356 Fin: true, 357 } 358 frame2 := wire.StreamFrame{ 359 Offset: 0, 360 Data: []byte{0xDE, 0xAD}, 361 } 362 err := str.handleStreamFrame(&frame1) 363 Expect(err).ToNot(HaveOccurred()) 364 err = str.handleStreamFrame(&frame2) 365 Expect(err).ToNot(HaveOccurred()) 366 mockSender.EXPECT().onStreamCompleted(streamID) 367 b := make([]byte, 4) 368 n, err := strWithTimeout.Read(b) 369 Expect(err).To(MatchError(io.EOF)) 370 Expect(n).To(Equal(4)) 371 Expect(b).To(Equal([]byte{0xDE, 0xAD, 0xBE, 0xEF})) 372 n, err = strWithTimeout.Read(b) 373 Expect(n).To(BeZero()) 374 Expect(err).To(MatchError(io.EOF)) 375 }) 376 377 It("returns EOFs with partial read", func() { 378 mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(2), true) 379 mockFC.EXPECT().AddBytesRead(protocol.ByteCount(2)) 380 err := str.handleStreamFrame(&wire.StreamFrame{ 381 Offset: 0, 382 Data: []byte{0xde, 0xad}, 383 Fin: true, 384 }) 385 Expect(err).ToNot(HaveOccurred()) 386 mockSender.EXPECT().onStreamCompleted(streamID) 387 b := make([]byte, 4) 388 n, err := strWithTimeout.Read(b) 389 Expect(err).To(MatchError(io.EOF)) 390 Expect(n).To(Equal(2)) 391 Expect(b[:n]).To(Equal([]byte{0xde, 0xad})) 392 }) 393 394 It("handles immediate FINs", func() { 395 mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(0), true) 396 mockFC.EXPECT().AddBytesRead(protocol.ByteCount(0)) 397 err := str.handleStreamFrame(&wire.StreamFrame{ 398 Offset: 0, 399 Fin: true, 400 }) 401 Expect(err).ToNot(HaveOccurred()) 402 mockSender.EXPECT().onStreamCompleted(streamID) 403 b := make([]byte, 4) 404 n, err := strWithTimeout.Read(b) 405 Expect(n).To(BeZero()) 406 Expect(err).To(MatchError(io.EOF)) 407 }) 408 409 // Calling Read concurrently doesn't make any sense (and is forbidden), 410 // but we still want to make sure that we don't complete the stream more than once 411 // if the user misuses our API. 412 // This would lead to an INTERNAL_ERROR ("tried to delete unknown outgoing stream"), 413 // which can be hard to debug. 414 // Note that even without the protection built into the receiveStream, this test 415 // is very timing-dependent, and would need to run a few hundred times to trigger the failure. 416 It("handles concurrent reads", func() { 417 mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(6), gomock.Any()).AnyTimes() 418 var bytesRead protocol.ByteCount 419 mockFC.EXPECT().AddBytesRead(gomock.Any()).Do(func(n protocol.ByteCount) { bytesRead += n }).AnyTimes() 420 421 var numCompleted int32 422 mockSender.EXPECT().onStreamCompleted(streamID).Do(func(protocol.StreamID) { 423 atomic.AddInt32(&numCompleted, 1) 424 }).AnyTimes() 425 const num = 3 426 var wg sync.WaitGroup 427 wg.Add(num) 428 for i := 0; i < num; i++ { 429 go func() { 430 defer wg.Done() 431 defer GinkgoRecover() 432 _, err := str.Read(make([]byte, 8)) 433 Expect(err).To(MatchError(io.EOF)) 434 }() 435 } 436 str.handleStreamFrame(&wire.StreamFrame{ 437 Offset: 0, 438 Data: []byte("foobar"), 439 Fin: true, 440 }) 441 wg.Wait() 442 Expect(bytesRead).To(BeEquivalentTo(6)) 443 Expect(atomic.LoadInt32(&numCompleted)).To(BeEquivalentTo(1)) 444 }) 445 }) 446 }) 447 448 Context("closing for shutdown", func() { 449 testErr := errors.New("test error") 450 451 It("immediately returns all reads", func() { 452 done := make(chan struct{}) 453 b := make([]byte, 4) 454 go func() { 455 defer GinkgoRecover() 456 n, err := strWithTimeout.Read(b) 457 Expect(n).To(BeZero()) 458 Expect(err).To(MatchError(testErr)) 459 close(done) 460 }() 461 Consistently(done).ShouldNot(BeClosed()) 462 str.closeForShutdown(testErr) 463 Eventually(done).Should(BeClosed()) 464 }) 465 466 It("errors for all following reads", func() { 467 str.closeForShutdown(testErr) 468 b := make([]byte, 1) 469 n, err := strWithTimeout.Read(b) 470 Expect(n).To(BeZero()) 471 Expect(err).To(MatchError(testErr)) 472 }) 473 }) 474 }) 475 476 Context("stream cancellations", func() { 477 Context("canceling read", func() { 478 It("unblocks Read", func() { 479 mockSender.EXPECT().queueControlFrame(gomock.Any()) 480 done := make(chan struct{}) 481 go func() { 482 defer GinkgoRecover() 483 _, err := strWithTimeout.Read([]byte{0}) 484 Expect(err).To(Equal(&StreamError{ 485 StreamID: streamID, 486 ErrorCode: 1234, 487 Remote: false, 488 })) 489 close(done) 490 }() 491 Consistently(done).ShouldNot(BeClosed()) 492 str.CancelRead(1234) 493 Eventually(done).Should(BeClosed()) 494 }) 495 496 It("doesn't allow further calls to Read", func() { 497 mockSender.EXPECT().queueControlFrame(gomock.Any()) 498 str.CancelRead(1234) 499 _, err := strWithTimeout.Read([]byte{0}) 500 Expect(err).To(Equal(&StreamError{ 501 StreamID: streamID, 502 ErrorCode: 1234, 503 Remote: false, 504 })) 505 }) 506 507 It("does nothing when CancelRead is called twice", func() { 508 mockSender.EXPECT().queueControlFrame(gomock.Any()) 509 str.CancelRead(1234) 510 str.CancelRead(1234) 511 _, err := strWithTimeout.Read([]byte{0}) 512 Expect(err).To(Equal(&StreamError{ 513 StreamID: streamID, 514 ErrorCode: 1234, 515 Remote: false, 516 })) 517 }) 518 519 It("queues a STOP_SENDING frame", func() { 520 mockSender.EXPECT().queueControlFrame(&wire.StopSendingFrame{ 521 StreamID: streamID, 522 ErrorCode: 1234, 523 }) 524 str.CancelRead(1234) 525 }) 526 527 It("doesn't send a STOP_SENDING frame, if the FIN was already read", func() { 528 mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(6), true) 529 mockFC.EXPECT().AddBytesRead(protocol.ByteCount(6)) 530 // no calls to mockSender.queueControlFrame 531 Expect(str.handleStreamFrame(&wire.StreamFrame{ 532 StreamID: streamID, 533 Data: []byte("foobar"), 534 Fin: true, 535 })).To(Succeed()) 536 mockSender.EXPECT().onStreamCompleted(streamID) 537 _, err := strWithTimeout.Read(make([]byte, 100)) 538 Expect(err).To(MatchError(io.EOF)) 539 str.CancelRead(1234) 540 }) 541 542 It("doesn't send a STOP_SENDING frame, if the stream was already reset", func() { 543 gomock.InOrder( 544 mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(42), true), 545 mockFC.EXPECT().Abandon(), 546 ) 547 mockSender.EXPECT().onStreamCompleted(streamID) 548 Expect(str.handleResetStreamFrame(&wire.ResetStreamFrame{ 549 StreamID: streamID, 550 FinalSize: 42, 551 })).To(Succeed()) 552 str.CancelRead(1234) 553 }) 554 555 It("sends a STOP_SENDING and completes the stream after receiving the final offset", func() { 556 mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(1000), true) 557 Expect(str.handleStreamFrame(&wire.StreamFrame{ 558 Offset: 1000, 559 Fin: true, 560 })).To(Succeed()) 561 mockFC.EXPECT().Abandon() 562 mockSender.EXPECT().queueControlFrame(gomock.Any()) 563 mockSender.EXPECT().onStreamCompleted(streamID) 564 str.CancelRead(1234) 565 }) 566 567 It("completes the stream when receiving the Fin after the stream was canceled", func() { 568 mockSender.EXPECT().queueControlFrame(gomock.Any()) 569 str.CancelRead(1234) 570 gomock.InOrder( 571 mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(1000), true), 572 mockFC.EXPECT().Abandon(), 573 ) 574 mockSender.EXPECT().onStreamCompleted(streamID) 575 Expect(str.handleStreamFrame(&wire.StreamFrame{ 576 Offset: 1000, 577 Fin: true, 578 })).To(Succeed()) 579 }) 580 581 It("handles duplicate FinBits after the stream was canceled", func() { 582 mockSender.EXPECT().queueControlFrame(gomock.Any()) 583 str.CancelRead(1234) 584 gomock.InOrder( 585 mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(1000), true), 586 mockFC.EXPECT().Abandon(), 587 mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(1000), true), 588 ) 589 mockSender.EXPECT().onStreamCompleted(streamID) 590 Expect(str.handleStreamFrame(&wire.StreamFrame{ 591 Offset: 1000, 592 Fin: true, 593 })).To(Succeed()) 594 Expect(str.handleStreamFrame(&wire.StreamFrame{ 595 Offset: 1000, 596 Fin: true, 597 })).To(Succeed()) 598 }) 599 }) 600 601 Context("receiving RESET_STREAM frames", func() { 602 rst := &wire.ResetStreamFrame{ 603 StreamID: streamID, 604 FinalSize: 42, 605 ErrorCode: 1234, 606 } 607 608 It("unblocks Read", func() { 609 done := make(chan struct{}) 610 go func() { 611 defer GinkgoRecover() 612 _, err := strWithTimeout.Read([]byte{0}) 613 Expect(err).To(Equal(&StreamError{ 614 StreamID: streamID, 615 ErrorCode: 1234, 616 Remote: true, 617 })) 618 close(done) 619 }() 620 Consistently(done).ShouldNot(BeClosed()) 621 mockSender.EXPECT().onStreamCompleted(streamID) 622 gomock.InOrder( 623 mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(42), true), 624 mockFC.EXPECT().Abandon(), 625 ) 626 Expect(str.handleResetStreamFrame(rst)).To(Succeed()) 627 Eventually(done).Should(BeClosed()) 628 }) 629 630 It("doesn't allow further calls to Read", func() { 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 _, err := strWithTimeout.Read([]byte{0}) 638 Expect(err).To(MatchError(&StreamError{ 639 StreamID: streamID, 640 ErrorCode: 1234, 641 })) 642 }) 643 644 It("errors when receiving a RESET_STREAM with an inconsistent offset", func() { 645 testErr := errors.New("already received a different final offset before") 646 mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(42), true).Return(testErr) 647 err := str.handleResetStreamFrame(rst) 648 Expect(err).To(MatchError(testErr)) 649 }) 650 651 It("ignores duplicate RESET_STREAM frames", func() { 652 mockSender.EXPECT().onStreamCompleted(streamID) 653 mockFC.EXPECT().Abandon() 654 mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(42), true).Times(2) 655 Expect(str.handleResetStreamFrame(rst)).To(Succeed()) 656 Expect(str.handleResetStreamFrame(rst)).To(Succeed()) 657 }) 658 659 It("doesn't call onStreamCompleted again when the final offset was already received via Fin", func() { 660 mockSender.EXPECT().queueControlFrame(gomock.Any()) 661 str.CancelRead(1234) 662 mockSender.EXPECT().onStreamCompleted(streamID) 663 mockFC.EXPECT().Abandon() 664 mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(42), true).Times(2) 665 Expect(str.handleStreamFrame(&wire.StreamFrame{ 666 StreamID: streamID, 667 Offset: rst.FinalSize, 668 Fin: true, 669 })).To(Succeed()) 670 Expect(str.handleResetStreamFrame(rst)).To(Succeed()) 671 }) 672 673 It("doesn't do anything when it was closed for shutdown", func() { 674 str.closeForShutdown(errors.New("shutdown")) 675 err := str.handleResetStreamFrame(rst) 676 Expect(err).ToNot(HaveOccurred()) 677 }) 678 }) 679 }) 680 681 Context("flow control", func() { 682 It("errors when a STREAM frame causes a flow control violation", func() { 683 testErr := errors.New("flow control violation") 684 mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(8), false).Return(testErr) 685 frame := wire.StreamFrame{ 686 Offset: 2, 687 Data: []byte("foobar"), 688 } 689 err := str.handleStreamFrame(&frame) 690 Expect(err).To(MatchError(testErr)) 691 }) 692 693 It("gets a window update", func() { 694 mockFC.EXPECT().GetWindowUpdate().Return(protocol.ByteCount(0x100)) 695 Expect(str.getWindowUpdate()).To(Equal(protocol.ByteCount(0x100))) 696 }) 697 }) 698 })