Remove synchronous Write APIs (#1838)
This commit is contained in:
parent
9ab09dbe48
commit
cf16d601d6
|
|
@ -503,64 +503,13 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Flush()
|
public async Task FlushAsync(CancellationToken cancellationToken = default(CancellationToken))
|
||||||
{
|
|
||||||
InitializeResponse(0).GetAwaiter().GetResult();
|
|
||||||
Output.Flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task FlushAsync(CancellationToken cancellationToken)
|
|
||||||
{
|
{
|
||||||
await InitializeResponse(0);
|
await InitializeResponse(0);
|
||||||
await Output.FlushAsync(cancellationToken);
|
await Output.FlushAsync(cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Write(ArraySegment<byte> data)
|
public Task WriteAsync(ArraySegment<byte> data, CancellationToken cancellationToken = default(CancellationToken))
|
||||||
{
|
|
||||||
// For the first write, ensure headers are flushed if Write(Chunked) isn't called.
|
|
||||||
var firstWrite = !HasResponseStarted;
|
|
||||||
|
|
||||||
if (firstWrite)
|
|
||||||
{
|
|
||||||
InitializeResponse(data.Count).GetAwaiter().GetResult();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
VerifyAndUpdateWrite(data.Count);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_canHaveBody)
|
|
||||||
{
|
|
||||||
if (_autoChunk)
|
|
||||||
{
|
|
||||||
if (data.Count == 0)
|
|
||||||
{
|
|
||||||
if (firstWrite)
|
|
||||||
{
|
|
||||||
Flush();
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
WriteChunked(data);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
CheckLastWrite();
|
|
||||||
Output.Write(data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
HandleNonBodyResponseWrite();
|
|
||||||
|
|
||||||
if (firstWrite)
|
|
||||||
{
|
|
||||||
Flush();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task WriteAsync(ArraySegment<byte> data, CancellationToken cancellationToken)
|
|
||||||
{
|
{
|
||||||
if (!HasResponseStarted)
|
if (!HasResponseStarted)
|
||||||
{
|
{
|
||||||
|
|
@ -679,11 +628,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void WriteChunked(ArraySegment<byte> data)
|
|
||||||
{
|
|
||||||
Output.Write(data, chunk: true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Task WriteChunkedAsync(ArraySegment<byte> data, CancellationToken cancellationToken)
|
private Task WriteChunkedAsync(ArraySegment<byte> data, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
return Output.WriteAsync(data, chunk: true, cancellationToken: cancellationToken);
|
return Output.WriteAsync(data, chunk: true, cancellationToken: cancellationToken);
|
||||||
|
|
@ -707,12 +651,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
StringValues expect;
|
|
||||||
if (_httpVersion == Http.HttpVersion.Http11 &&
|
if (_httpVersion == Http.HttpVersion.Http11 &&
|
||||||
RequestHeaders.TryGetValue("Expect", out expect) &&
|
RequestHeaders.TryGetValue("Expect", out var expect) &&
|
||||||
(expect.FirstOrDefault() ?? "").Equals("100-continue", StringComparison.OrdinalIgnoreCase))
|
(expect.FirstOrDefault() ?? "").Equals("100-continue", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
Output.Write(_continueBytes);
|
Output.WriteAsync(_continueBytes).GetAwaiter().GetResult();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,9 +33,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
|
|
||||||
public override void Flush()
|
public override void Flush()
|
||||||
{
|
{
|
||||||
ValidateState(default(CancellationToken));
|
FlushAsync(default(CancellationToken)).GetAwaiter().GetResult();
|
||||||
|
|
||||||
_frameControl.Flush();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Task FlushAsync(CancellationToken cancellationToken)
|
public override Task FlushAsync(CancellationToken cancellationToken)
|
||||||
|
|
@ -60,9 +58,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
|
|
||||||
public override void Write(byte[] buffer, int offset, int count)
|
public override void Write(byte[] buffer, int offset, int count)
|
||||||
{
|
{
|
||||||
ValidateState(default(CancellationToken));
|
WriteAsync(buffer, offset, count, default(CancellationToken)).GetAwaiter().GetResult();
|
||||||
|
|
||||||
_frameControl.Write(new ArraySegment<byte>(buffer, offset, count));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
|
public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
|
||||||
|
|
|
||||||
|
|
@ -10,9 +10,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
public interface IFrameControl
|
public interface IFrameControl
|
||||||
{
|
{
|
||||||
void ProduceContinue();
|
void ProduceContinue();
|
||||||
void Write(ArraySegment<byte> data);
|
|
||||||
Task WriteAsync(ArraySegment<byte> data, CancellationToken cancellationToken);
|
Task WriteAsync(ArraySegment<byte> data, CancellationToken cancellationToken);
|
||||||
void Flush();
|
|
||||||
Task FlushAsync(CancellationToken cancellationToken);
|
Task FlushAsync(CancellationToken cancellationToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -39,11 +39,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
_flushCompleted = OnFlushCompleted;
|
_flushCompleted = OnFlushCompleted;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Write(ArraySegment<byte> buffer, bool chunk = false)
|
|
||||||
{
|
|
||||||
WriteAsync(buffer, default(CancellationToken), chunk).GetAwaiter().GetResult();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task WriteAsync(ArraySegment<byte> buffer, bool chunk = false, CancellationToken cancellationToken = default(CancellationToken))
|
public Task WriteAsync(ArraySegment<byte> buffer, bool chunk = false, CancellationToken cancellationToken = default(CancellationToken))
|
||||||
{
|
{
|
||||||
if (cancellationToken.IsCancellationRequested)
|
if (cancellationToken.IsCancellationRequested)
|
||||||
|
|
@ -54,11 +49,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
return WriteAsync(buffer, cancellationToken, chunk);
|
return WriteAsync(buffer, cancellationToken, chunk);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Flush()
|
|
||||||
{
|
|
||||||
WriteAsync(_emptyData, default(CancellationToken)).GetAwaiter().GetResult();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task FlushAsync(CancellationToken cancellationToken = default(CancellationToken))
|
public Task FlushAsync(CancellationToken cancellationToken = default(CancellationToken))
|
||||||
{
|
{
|
||||||
return WriteAsync(_emptyData, cancellationToken);
|
return WriteAsync(_emptyData, cancellationToken);
|
||||||
|
|
|
||||||
|
|
@ -211,10 +211,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void ThrowsWhenStatusCodeIsSetAfterResponseStarted()
|
public async Task ThrowsWhenStatusCodeIsSetAfterResponseStarted()
|
||||||
{
|
{
|
||||||
// Act
|
// Act
|
||||||
_frame.Write(new ArraySegment<byte>(new byte[1]));
|
await _frame.WriteAsync(new ArraySegment<byte>(new byte[1]));
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.True(_frame.HasResponseStarted);
|
Assert.True(_frame.HasResponseStarted);
|
||||||
|
|
@ -222,10 +222,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void ThrowsWhenReasonPhraseIsSetAfterResponseStarted()
|
public async Task ThrowsWhenReasonPhraseIsSetAfterResponseStarted()
|
||||||
{
|
{
|
||||||
// Act
|
// Act
|
||||||
_frame.Write(new ArraySegment<byte>(new byte[1]));
|
await _frame.WriteAsync(new ArraySegment<byte>(new byte[1]));
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.True(_frame.HasResponseStarted);
|
Assert.True(_frame.HasResponseStarted);
|
||||||
|
|
@ -233,9 +233,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void ThrowsWhenOnStartingIsSetAfterResponseStarted()
|
public async Task ThrowsWhenOnStartingIsSetAfterResponseStarted()
|
||||||
{
|
{
|
||||||
_frame.Write(new ArraySegment<byte>(new byte[1]));
|
await _frame.WriteAsync(new ArraySegment<byte>(new byte[1]));
|
||||||
|
|
||||||
// Act/Assert
|
// Act/Assert
|
||||||
Assert.True(_frame.HasResponseStarted);
|
Assert.True(_frame.HasResponseStarted);
|
||||||
|
|
@ -472,13 +472,13 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void WriteThrowsForNonBodyResponse()
|
public async Task WriteThrowsForNonBodyResponse()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
((IHttpResponseFeature)_frame).StatusCode = StatusCodes.Status304NotModified;
|
((IHttpResponseFeature)_frame).StatusCode = StatusCodes.Status304NotModified;
|
||||||
|
|
||||||
// Act/Assert
|
// Act/Assert
|
||||||
Assert.Throws<InvalidOperationException>(() => _frame.Write(new ArraySegment<byte>(new byte[1])));
|
await Assert.ThrowsAsync<InvalidOperationException>(() => _frame.WriteAsync(new ArraySegment<byte>(new byte[1])));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -493,14 +493,14 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void WriteDoesNotThrowForHeadResponse()
|
public async Task WriteDoesNotThrowForHeadResponse()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
_frame.HttpVersion = "HTTP/1.1";
|
_frame.HttpVersion = "HTTP/1.1";
|
||||||
((IHttpRequestFeature)_frame).Method = "HEAD";
|
((IHttpRequestFeature)_frame).Method = "HEAD";
|
||||||
|
|
||||||
// Act/Assert
|
// Act/Assert
|
||||||
_frame.Write(new ArraySegment<byte>(new byte[1]));
|
await _frame.WriteAsync(new ArraySegment<byte>(new byte[1]));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -515,7 +515,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void ManuallySettingTransferEncodingThrowsForHeadResponse()
|
public async Task ManuallySettingTransferEncodingThrowsForHeadResponse()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
_frame.HttpVersion = "HTTP/1.1";
|
_frame.HttpVersion = "HTTP/1.1";
|
||||||
|
|
@ -525,11 +525,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
_frame.ResponseHeaders.Add("Transfer-Encoding", "chunked");
|
_frame.ResponseHeaders.Add("Transfer-Encoding", "chunked");
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Throws<InvalidOperationException>(() => _frame.Flush());
|
await Assert.ThrowsAsync<InvalidOperationException>(() => _frame.FlushAsync());
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void ManuallySettingTransferEncodingThrowsForNoBodyResponse()
|
public async Task ManuallySettingTransferEncodingThrowsForNoBodyResponse()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
_frame.HttpVersion = "HTTP/1.1";
|
_frame.HttpVersion = "HTTP/1.1";
|
||||||
|
|
@ -539,7 +539,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
_frame.ResponseHeaders.Add("Transfer-Encoding", "chunked");
|
_frame.ResponseHeaders.Add("Transfer-Encoding", "chunked");
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Throws<InvalidOperationException>(() => _frame.Flush());
|
await Assert.ThrowsAsync<InvalidOperationException>(() => _frame.FlushAsync());
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -558,7 +558,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void RequestAbortedTokenIsResetBeforeLastWriteWithContentLength()
|
public async Task RequestAbortedTokenIsResetBeforeLastWriteWithContentLength()
|
||||||
{
|
{
|
||||||
_frame.ResponseHeaders["Content-Length"] = "12";
|
_frame.ResponseHeaders["Content-Length"] = "12";
|
||||||
|
|
||||||
|
|
@ -567,11 +567,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
|
|
||||||
foreach (var ch in "hello, worl")
|
foreach (var ch in "hello, worl")
|
||||||
{
|
{
|
||||||
_frame.Write(new ArraySegment<byte>(new[] { (byte)ch }));
|
await _frame.WriteAsync(new ArraySegment<byte>(new[] { (byte)ch }));
|
||||||
Assert.Same(original, _frame.RequestAborted.WaitHandle);
|
Assert.Same(original, _frame.RequestAborted.WaitHandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
_frame.Write(new ArraySegment<byte>(new[] { (byte)'d' }));
|
await _frame.WriteAsync(new ArraySegment<byte>(new[] { (byte)'d' }));
|
||||||
Assert.NotSame(original, _frame.RequestAborted.WaitHandle);
|
Assert.NotSame(original, _frame.RequestAborted.WaitHandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,10 +11,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests.TestHelpers
|
||||||
{
|
{
|
||||||
public class MockFrameControl : IFrameControl
|
public class MockFrameControl : IFrameControl
|
||||||
{
|
{
|
||||||
public void Flush()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task FlushAsync(CancellationToken cancellationToken)
|
public Task FlushAsync(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
return TaskCache.CompletedTask;
|
return TaskCache.CompletedTask;
|
||||||
|
|
@ -24,10 +20,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests.TestHelpers
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Write(ArraySegment<byte> data)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task WriteAsync(ArraySegment<byte> data, CancellationToken cancellationToken)
|
public Task WriteAsync(ArraySegment<byte> data, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
return TaskCache.CompletedTask;
|
return TaskCache.CompletedTask;
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
FrameContext.FrameControl = this;
|
FrameContext.FrameControl = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IPipe Pipe { get; }
|
public IPipe Pipe { get; }
|
||||||
|
|
||||||
public Frame FrameContext { get; set; }
|
public Frame FrameContext { get; set; }
|
||||||
|
|
||||||
|
|
@ -70,23 +70,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void IFrameControl.ProduceContinue()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void IFrameControl.Write(ArraySegment<byte> data)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
Task IFrameControl.WriteAsync(ArraySegment<byte> data, CancellationToken cancellationToken)
|
Task IFrameControl.WriteAsync(ArraySegment<byte> data, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
return TaskCache.CompletedTask;
|
return TaskCache.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
void IFrameControl.Flush()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
Task IFrameControl.FlushAsync(CancellationToken cancellationToken)
|
Task IFrameControl.FlushAsync(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
return TaskCache.CompletedTask;
|
return TaskCache.CompletedTask;
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@ using Microsoft.AspNetCore.Server.Kestrel.Core;
|
||||||
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal;
|
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal;
|
||||||
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
|
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
|
||||||
using Microsoft.AspNetCore.Server.Kestrel.Internal.System.IO.Pipelines;
|
using Microsoft.AspNetCore.Server.Kestrel.Internal.System.IO.Pipelines;
|
||||||
using Microsoft.AspNetCore.Server.Kestrel.Performance.Mocks;
|
|
||||||
using Microsoft.AspNetCore.Testing;
|
using Microsoft.AspNetCore.Testing;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Server.Kestrel.Performance
|
namespace Microsoft.AspNetCore.Server.Kestrel.Performance
|
||||||
|
|
@ -38,18 +37,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
|
||||||
_frameChunked.RequestHeaders.Add("Transfer-Encoding", "chunked");
|
_frameChunked.RequestHeaders.Add("Transfer-Encoding", "chunked");
|
||||||
}
|
}
|
||||||
|
|
||||||
[Benchmark]
|
|
||||||
public void Write()
|
|
||||||
{
|
|
||||||
_frame.Write(new ArraySegment<byte>(_writeData));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Benchmark]
|
|
||||||
public void WriteChunked()
|
|
||||||
{
|
|
||||||
_frameChunked.Write(new ArraySegment<byte>(_writeData));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Benchmark]
|
[Benchmark]
|
||||||
public async Task WriteAsync()
|
public async Task WriteAsync()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue