public async Task StopAsyncPreventsFurtherDataConsumption() { using (var input = new TestInput()) { var body = Http1MessageBody.For(HttpVersion.Http11, new HttpRequestHeaders { HeaderContentLength = "2" }, input.Http1Connection); var stream = new HttpRequestStream(Mock.Of <IHttpBodyControlFeature>()); stream.StartAcceptingReads(body); // Add some input and consume it to ensure PumpAsync is running input.Add("a"); Assert.Equal(1, await stream.ReadAsync(new byte[1], 0, 1)); await body.StopAsync(); // Add some more data. Checking for cancelation and exiting the loop // should take priority over reading this data. input.Add("b"); // There shouldn't be any additional data available Assert.Equal(0, await stream.ReadAsync(new byte[1], 0, 1)); } }
public async Task OnlyEnforcesRequestBodyTimeoutAfterSending100Continue() { using (var input = new TestInput()) { var produceContinueCalled = false; var startTimingReadsCalledAfterProduceContinue = false; var mockHttpResponseControl = new Mock <IHttpResponseControl>(); mockHttpResponseControl .Setup(httpResponseControl => httpResponseControl.ProduceContinue()) .Callback(() => produceContinueCalled = true); input.Http1Connection.HttpResponseControl = mockHttpResponseControl.Object; var minReadRate = input.Http1Connection.MinRequestBodyDataRate; var mockTimeoutControl = new Mock <ITimeoutControl>(); mockTimeoutControl .Setup(timeoutControl => timeoutControl.StartTimingReads(minReadRate)) .Callback(() => startTimingReadsCalledAfterProduceContinue = produceContinueCalled); input.Http1ConnectionContext.TimeoutControl = mockTimeoutControl.Object; var body = Http1MessageBody.For(HttpVersion.Http11, new HttpRequestHeaders { HeaderContentLength = "5" }, input.Http1Connection); // Add some input and read it to start PumpAsync var readTask = body.ReadAsync(new ArraySegment <byte>(new byte[1])); Assert.True(startTimingReadsCalledAfterProduceContinue); input.Add("a"); await readTask; await body.StopAsync(); } }
public async Task CanReadAsyncFromRemainingData(HttpVersion httpVersion) { using (var input = new TestInput()) { var body = Http1MessageBody.For(httpVersion, new HttpRequestHeaders { HeaderConnection = "upgrade" }, input.Http1Connection); var stream = new HttpRequestStream(Mock.Of <IHttpBodyControlFeature>()); stream.StartAcceptingReads(body); input.Add("Hello"); var buffer = new byte[1024]; var count = await stream.ReadAsync(buffer, 0, buffer.Length); Assert.Equal(5, count); AssertASCII("Hello", new ArraySegment <byte>(buffer, 0, count)); input.Fin(); await body.StopAsync(); } }
public async Task PumpAsyncDoesNotReturnAfterCancelingInput() { using (var input = new TestInput()) { var body = Http1MessageBody.For(HttpVersion.Http11, new HttpRequestHeaders { HeaderContentLength = "2" }, input.Http1Connection); var stream = new HttpRequestStream(Mock.Of <IHttpBodyControlFeature>()); stream.StartAcceptingReads(body); // Add some input and consume it to ensure PumpAsync is running input.Add("a"); Assert.Equal(1, await stream.ReadAsync(new byte[1], 0, 1)); input.Transport.Input.CancelPendingRead(); // Add more input and verify is read input.Add("b"); Assert.Equal(1, await stream.ReadAsync(new byte[1], 0, 1)); input.Http1Connection.RequestBodyPipe.Reader.Complete(); await body.StopAsync(); } }
public async Task CopyToAsyncDoesNotCopyBlocks() { var writeCount = 0; var writeTcs = new TaskCompletionSource <(byte[], int, int)>(); var mockDestination = new Mock <Stream>() { CallBase = true }; mockDestination .Setup(m => m.WriteAsync(It.IsAny <byte[]>(), It.IsAny <int>(), It.IsAny <int>(), CancellationToken.None)) .Callback((byte[] buffer, int offset, int count, CancellationToken cancellationToken) => { writeTcs.SetResult((buffer, offset, count)); writeCount++; }) .Returns(Task.CompletedTask); using (var memoryPool = KestrelMemoryPool.Create()) { var options = new PipeOptions(pool: memoryPool, readerScheduler: PipeScheduler.Inline, writerScheduler: PipeScheduler.Inline, useSynchronizationContext: false); var pair = DuplexPipe.CreateConnectionPair(options, options); var transport = pair.Transport; var application = pair.Application; var http1ConnectionContext = new Http1ConnectionContext { ServiceContext = new TestServiceContext(), ConnectionFeatures = new FeatureCollection(), Application = application, Transport = transport, MemoryPool = memoryPool, TimeoutControl = Mock.Of <ITimeoutControl>() }; var http1Connection = new Http1Connection(http1ConnectionContext) { HasStartedConsumingRequestBody = true }; var headers = new HttpRequestHeaders { HeaderContentLength = "12" }; var body = Http1MessageBody.For(HttpVersion.Http11, headers, http1Connection); var copyToAsyncTask = body.CopyToAsync(mockDestination.Object); var bytes = Encoding.ASCII.GetBytes("Hello "); var buffer = http1Connection.RequestBodyPipe.Writer.GetMemory(2048); ArraySegment <byte> segment; Assert.True(MemoryMarshal.TryGetArray(buffer, out segment)); Buffer.BlockCopy(bytes, 0, segment.Array, segment.Offset, bytes.Length); http1Connection.RequestBodyPipe.Writer.Advance(bytes.Length); await http1Connection.RequestBodyPipe.Writer.FlushAsync(); // Verify the block passed to Stream.WriteAsync() is the same one incoming data was written into. Assert.Equal((segment.Array, segment.Offset, bytes.Length), await writeTcs.Task); // Verify the again when GetMemory returns the tail space of the same block. writeTcs = new TaskCompletionSource <(byte[], int, int)>(); bytes = Encoding.ASCII.GetBytes("World!"); buffer = http1Connection.RequestBodyPipe.Writer.GetMemory(2048); Assert.True(MemoryMarshal.TryGetArray(buffer, out segment)); Buffer.BlockCopy(bytes, 0, segment.Array, segment.Offset, bytes.Length); http1Connection.RequestBodyPipe.Writer.Advance(bytes.Length); await http1Connection.RequestBodyPipe.Writer.FlushAsync(); Assert.Equal((segment.Array, segment.Offset, bytes.Length), await writeTcs.Task); http1Connection.RequestBodyPipe.Writer.Complete(); await copyToAsyncTask; Assert.Equal(2, writeCount); // Don't call body.StopAsync() because PumpAsync() was never called. http1Connection.RequestBodyPipe.Reader.Complete(); } }