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