|
10 | 10 | using System.Threading;
|
11 | 11 | using System.Threading.Tasks;
|
12 | 12 | using Microsoft.AspNetCore.Connections;
|
| 13 | +using Microsoft.AspNetCore.Http; |
13 | 14 | using Microsoft.AspNetCore.Server.Kestrel.Core.Features;
|
14 | 15 | using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2;
|
15 | 16 | using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2.HPack;
|
@@ -682,6 +683,100 @@ await ExpectAsync(Http2FrameType.DATA,
|
682 | 683 | Assert.Equal(updateSize, connectionWindowUpdateFrame.WindowUpdateSizeIncrement);
|
683 | 684 | }
|
684 | 685 |
|
| 686 | + [Fact] |
| 687 | + public async Task DATA_BufferRequestBodyLargerThanStreamSizeSmallerThanConnectionPipe_Works() |
| 688 | + { |
| 689 | + var initialStreamWindowSize = _serviceContext.ServerOptions.Limits.Http2.InitialStreamWindowSize; |
| 690 | + var framesInStreamWindow = initialStreamWindowSize / Http2PeerSettings.DefaultMaxFrameSize; |
| 691 | + var initialConnectionWindowSize = _serviceContext.ServerOptions.Limits.Http2.InitialConnectionWindowSize; |
| 692 | + var framesInConnectionWindow = initialConnectionWindowSize / Http2PeerSettings.DefaultMaxFrameSize; |
| 693 | + |
| 694 | + // Grow the client stream windows so no stream WINDOW_UPDATEs need to be sent. |
| 695 | + _clientSettings.InitialWindowSize = int.MaxValue; |
| 696 | + |
| 697 | + await InitializeConnectionAsync(async context => |
| 698 | + { |
| 699 | + await context.Response.BodyWriter.FlushAsync(); |
| 700 | + var readResult = await context.Request.BodyReader.ReadAsync(); |
| 701 | + while (readResult.Buffer.Length != _maxData.Length * 4) |
| 702 | + { |
| 703 | + context.Request.BodyReader.AdvanceTo(readResult.Buffer.Start, readResult.Buffer.End); |
| 704 | + readResult = await context.Request.BodyReader.ReadAsync(); |
| 705 | + } |
| 706 | + |
| 707 | + context.Request.BodyReader.AdvanceTo(readResult.Buffer.Start, readResult.Buffer.End); |
| 708 | + |
| 709 | + readResult = await context.Request.BodyReader.ReadAsync(); |
| 710 | + Assert.Equal(readResult.Buffer.Length, _maxData.Length * 5); |
| 711 | + |
| 712 | + await context.Response.BodyWriter.WriteAsync(readResult.Buffer.ToArray()); |
| 713 | + |
| 714 | + context.Request.BodyReader.AdvanceTo(readResult.Buffer.End); |
| 715 | + }); |
| 716 | + |
| 717 | + // Grow the client connection windows so no connection WINDOW_UPDATEs need to be sent. |
| 718 | + await SendWindowUpdateAsync(0, int.MaxValue - (int)Http2PeerSettings.DefaultInitialWindowSize); |
| 719 | + |
| 720 | + await StartStreamAsync(1, _browserRequestHeaders, endStream: false); |
| 721 | + |
| 722 | + // Rounds down so we don't go over the half window size and trigger an update |
| 723 | + for (var i = 0; i < framesInStreamWindow / 2; i++) |
| 724 | + { |
| 725 | + await SendDataAsync(1, _maxData, endStream: false); |
| 726 | + } |
| 727 | + |
| 728 | + // trip over the update size. |
| 729 | + await SendDataAsync(1, _maxData, endStream: false); |
| 730 | + |
| 731 | + await ExpectAsync(Http2FrameType.HEADERS, |
| 732 | + withLength: 37, |
| 733 | + withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, |
| 734 | + withStreamId: 1); |
| 735 | + |
| 736 | + var dataFrames = new List<Http2FrameWithPayload>(); |
| 737 | + |
| 738 | + var streamWindowUpdateFrame1 = await ExpectAsync(Http2FrameType.WINDOW_UPDATE, |
| 739 | + withLength: 4, |
| 740 | + withFlags: (byte)Http2DataFrameFlags.NONE, |
| 741 | + withStreamId: 1); |
| 742 | + |
| 743 | + // Writing over half the initial window size induces both a connection-level and stream-level window update. |
| 744 | + |
| 745 | + await SendDataAsync(1, _maxData, endStream: true); |
| 746 | + |
| 747 | + for (var i = 0; i < framesInStreamWindow / 2 + 2; i++) |
| 748 | + { |
| 749 | + var dataFrame3 = await ExpectAsync(Http2FrameType.DATA, |
| 750 | + withLength: _maxData.Length, |
| 751 | + withFlags: (byte)Http2DataFrameFlags.NONE, |
| 752 | + withStreamId: 1); |
| 753 | + dataFrames.Add(dataFrame3); |
| 754 | + } |
| 755 | + |
| 756 | + var connectionWindowUpdateFrame = await ExpectAsync(Http2FrameType.WINDOW_UPDATE, |
| 757 | + withLength: 4, |
| 758 | + withFlags: (byte)Http2DataFrameFlags.NONE, |
| 759 | + withStreamId: 0); |
| 760 | + // End |
| 761 | + |
| 762 | + await ExpectAsync(Http2FrameType.DATA, |
| 763 | + withLength: 0, |
| 764 | + withFlags: (byte)Http2DataFrameFlags.END_STREAM, |
| 765 | + withStreamId: 1); |
| 766 | + |
| 767 | + await StopConnectionAsync(expectedLastStreamId: 1, ignoreNonGoAwayFrames: false); |
| 768 | + |
| 769 | + foreach (var frame in dataFrames) |
| 770 | + { |
| 771 | + Assert.True(_maxData.AsSpan().SequenceEqual(frame.PayloadSequence.ToArray())); |
| 772 | + } |
| 773 | + |
| 774 | + var updateSize = ((framesInStreamWindow / 2) + 1) * _maxData.Length; |
| 775 | + Assert.Equal(updateSize, streamWindowUpdateFrame1.WindowUpdateSizeIncrement); |
| 776 | + updateSize = ((framesInConnectionWindow / 2) + 1) * _maxData.Length; |
| 777 | + Assert.Equal(updateSize, connectionWindowUpdateFrame.WindowUpdateSizeIncrement); |
| 778 | + } |
| 779 | + |
685 | 780 | [Fact]
|
686 | 781 | public async Task DATA_Received_StreamIdZero_ConnectionError()
|
687 | 782 | {
|
|
0 commit comments