Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line numberDiff line numberDiff line change
Expand Up@@ -122,9 +122,9 @@ private void CloseWebSocket()
}
}

public abstract class GenericLoopbackConnection : IDisposable
public abstract class GenericLoopbackConnection : IAsyncDisposable
{
public abstract void Dispose();
public abstract ValueTask DisposeAsync();

public abstract Task InitializeConnectionAsync();

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -838,12 +838,12 @@ public async Task SendResponseBodyAsync(int streamId, ReadOnlyMemory<byte> respo
await SendResponseDataAsync(streamId, responseBody, isFinal).ConfigureAwait(false);
}

public override void Dispose()
public override async ValueTask DisposeAsync()
{
// Might have been already shutdown manually via WaitForConnectionShutdownAsync which nulls the _connectionStream.
if (_connectionStream != null)
{
ShutdownIgnoringErrorsAsync(_lastStreamId).GetAwaiter().GetResult();
await ShutdownIgnoringErrorsAsync(_lastStreamId);
}
}

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -148,15 +148,15 @@ public override void Dispose()

public override async Task<HttpRequestData> HandleRequestAsync(HttpStatusCode statusCode = HttpStatusCode.OK, IList<HttpHeaderData> headers = null, string content = "")
{
using (Http2LoopbackConnection connection = await EstablishConnectionAsync().ConfigureAwait(false))
await using (Http2LoopbackConnection connection = await EstablishConnectionAsync().ConfigureAwait(false))
{
return await connection.HandleRequestAsync(statusCode, headers, content).ConfigureAwait(false);
}
}

public override async Task AcceptConnectionAsync(Func<GenericLoopbackConnection, Task> funcAsync)
{
using (Http2LoopbackConnection connection = await EstablishConnectionAsync().ConfigureAwait(false))
await using (Http2LoopbackConnection connection = await EstablishConnectionAsync().ConfigureAwait(false))
{
await funcAsync(connection).ConfigureAwait(false);
}
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -56,17 +56,17 @@ public Http3LoopbackConnection(QuicConnection connection)

public long MaxHeaderListSize { get; private set; } = -1;

public override void Dispose()
public override async ValueTask DisposeAsync()
{
// Close any remaining request streams (but NOT control streams, as these should not be closed while the connection is open)
foreach (Http3LoopbackStream stream in _openStreams.Values)
{
stream.Dispose();
await stream.DisposeAsync().ConfigureAwait(false);
}

foreach (QuicStream stream in _delayedStreams)
{
stream.Dispose();
await stream.DisposeAsync().ConfigureAwait(false);
}

// We don't dispose the connection currently, because this causes races when the server connection is closed before
Expand All@@ -79,8 +79,8 @@ public override void Dispose()
_connection.Dispose();

// Dispose control streams so that we release their handles too.
_inboundControlStream?.Dispose();
_outboundControlStream?.Dispose();
await _inboundControlStream?.DisposeAsync().ConfigureAwait(false);
await _outboundControlStream?.DisposeAsync().ConfigureAwait(false);
#endif
}

Expand All@@ -91,20 +91,20 @@ public async Task CloseAsync(long errorCode)

public async ValueTask<Http3LoopbackStream> OpenUnidirectionalStreamAsync()
{
return new Http3LoopbackStream(await _connection.OpenUnidirectionalStreamAsync());
return new Http3LoopbackStream(await _connection.OpenOutboundStreamAsync(QuicStreamType.Unidirectional));
}

public async ValueTask<Http3LoopbackStream> OpenBidirectionalStreamAsync()
{
return new Http3LoopbackStream(await _connection.OpenBidirectionalStreamAsync());
return new Http3LoopbackStream(await _connection.OpenOutboundStreamAsync(QuicStreamType.Bidirectional));
}

public static int GetRequestId(QuicStream stream)
{
Debug.Assert(stream.CanRead && stream.CanWrite, "Stream must be a request stream.");

// TODO: QUIC streams can have IDs larger than int.MaxValue; update all our tests to use long rather than int.
return checked((int)stream.StreamId + 1);
return checked((int)stream.Id + 1);
}

public Http3LoopbackStream GetOpenRequest(int requestId = 0)
Expand All@@ -131,7 +131,7 @@ async Task EnsureControlStreamAcceptedInternalAsync()

while (true)
{
QuicStream quicStream = await _connection.AcceptStreamAsync().ConfigureAwait(false);
QuicStream quicStream = await _connection.AcceptInboundStreamAsync().ConfigureAwait(false);

if (!quicStream.CanWrite)
{
Expand DownExpand Up@@ -165,16 +165,16 @@ public async Task<Http3LoopbackStream> AcceptRequestStreamAsync()

if (!_delayedStreams.TryDequeue(out QuicStream quicStream))
{
quicStream = await _connection.AcceptStreamAsync().ConfigureAwait(false);
quicStream = await _connection.AcceptInboundStreamAsync().ConfigureAwait(false);
}

var stream = new Http3LoopbackStream(quicStream);

Assert.True(quicStream.CanWrite, "Expected writeable stream.");

_openStreams.Add(checked((int)quicStream.StreamId), stream);
_openStreams.Add(checked((int)quicStream.Id), stream);
_currentStream = stream;
_currentStreamId = quicStream.StreamId;
_currentStreamId = quicStream.Id;

return stream;
}
Expand DownExpand Up@@ -293,9 +293,9 @@ public async Task WaitForClientDisconnectAsync(bool refuseNewRequests = true)
break;
}

using (stream)
await using (stream)
{
await stream.AbortAndWaitForShutdownAsync(H3_REQUEST_REJECTED);
stream.Abort(H3_REQUEST_REJECTED);
}
}

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -36,8 +36,10 @@ public Http3LoopbackServer(Http3Options options = null)
{
var serverOptions = new QuicServerConnectionOptions()
{
MaxBidirectionalStreams = options.MaxBidirectionalStreams,
MaxUnidirectionalStreams = options.MaxUnidirectionalStreams,
DefaultStreamErrorCode = Http3LoopbackConnection.H3_REQUEST_CANCELLED,
DefaultCloseErrorCode = Http3LoopbackConnection.H3_NO_ERROR,
MaxInboundBidirectionalStreams = options.MaxInboundBidirectionalStreams,
MaxInboundUnidirectionalStreams = options.MaxInboundUnidirectionalStreams,
ServerAuthenticationOptions = new SslServerAuthenticationOptions
{
EnabledSslProtocols = options.SslProtocols,
Expand DownExpand Up@@ -80,14 +82,14 @@ public override async Task<GenericLoopbackConnection> EstablishGenericConnection

public override async Task AcceptConnectionAsync(Func<GenericLoopbackConnection, Task> funcAsync)
{
using Http3LoopbackConnection con = await EstablishHttp3ConnectionAsync().ConfigureAwait(false);
await using Http3LoopbackConnection con = await EstablishHttp3ConnectionAsync().ConfigureAwait(false);
await funcAsync(con).ConfigureAwait(false);
await con.ShutdownAsync();
}

public override async Task<HttpRequestData> HandleRequestAsync(HttpStatusCode statusCode = HttpStatusCode.OK, IList<HttpHeaderData> headers = null, string content = "")
{
using var con = (Http3LoopbackConnection)await EstablishGenericConnectionAsync().ConfigureAwait(false);
await using Http3LoopbackConnection con = (Http3LoopbackConnection)await EstablishGenericConnectionAsync().ConfigureAwait(false);
return await con.HandleRequestAsync(statusCode, headers, content).ConfigureAwait(false);
}
}
Expand DownExpand Up@@ -136,16 +138,16 @@ private static Http3Options CreateOptions(GenericLoopbackOptions options)
}
public class Http3Options : GenericLoopbackOptions
{
public int MaxUnidirectionalStreams { get; set; }
public int MaxInboundUnidirectionalStreams { get; set; }

public int MaxBidirectionalStreams { get; set; }
public int MaxInboundBidirectionalStreams { get; set; }

public string Alpn { get; set; }

public Http3Options()
{
MaxUnidirectionalStreams = 10;
MaxBidirectionalStreams = 100;
MaxInboundUnidirectionalStreams = 10;
MaxInboundBidirectionalStreams = 100;
Alpn = SslApplicationProtocol.Http3.ToString();
}
}
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -15,7 +15,7 @@
namespace System.Net.Test.Common
{

internal sealed class Http3LoopbackStream : IDisposable
internal sealed class Http3LoopbackStream : IAsyncDisposable
{
private const int MaximumVarIntBytes = 8;
private const long VarIntMax = (1L << 62) - 1;
Expand All@@ -40,12 +40,9 @@ public Http3LoopbackStream(QuicStream stream)
_stream = stream;
}

public void Dispose()
{
_stream.Dispose();
}
public ValueTask DisposeAsync() => _stream.DisposeAsync();

public long StreamId => _stream.StreamId;
public long StreamId => _stream.Id;

public async Task<HttpRequestData> HandleRequestAsync(HttpStatusCode statusCode = HttpStatusCode.OK, IList<HttpHeaderData> headers = null, string content = "")
{
Expand DownExpand Up@@ -285,9 +282,7 @@ public async Task SendResponseBodyAsync(byte[] content, bool isFinal = true)

if (isFinal)
{
_stream.Shutdown();
await _stream.ShutdownCompleted().ConfigureAwait(false);
Dispose();
_stream.CompleteWrites();
}
}

Expand DownExpand Up@@ -389,7 +384,7 @@ async Task WaitForWriteCancellation()
{
try
{
await _stream.WaitForWriteCompletionAsync();
await _stream.WritesClosed;
}
catch (QuicException ex) when (ex.QuicError == QuicError.StreamAborted && ex.ApplicationErrorCode == Http3LoopbackConnection.H3_REQUEST_CANCELLED)
{
Expand DownExpand Up@@ -424,11 +419,9 @@ private async Task DrainResponseData()
}
}

public async Task AbortAndWaitForShutdownAsync(long errorCode)
public void Abort(long errorCode)
{
_stream.AbortRead(errorCode);
_stream.AbortWrite(errorCode);
await _stream.ShutdownCompleted();
_stream.Abort(QuicAbortDirection.Both, errorCode);
}

public async Task<(long? frameType, byte[] payload)> ReadFrameAsync()
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -109,15 +109,18 @@ public override async Task<GenericLoopbackConnection> EstablishGenericConnection
{
return connection = await Http2LoopbackServerFactory.Singleton.CreateConnectionAsync(new SocketWrapper(socket), stream, options).ConfigureAwait(false);
}
else
else
{
throw new Exception($"Invalid ClearTextVersion={_options.ClearTextVersion} specified");
}
}
catch
{
connection?.Dispose();
connection = null;
{
if (connection is not null)
{
await connection.DisposeAsync();
connection = null;
}
stream.Dispose();
throw;
}
Expand All@@ -132,15 +135,15 @@ public override async Task<GenericLoopbackConnection> EstablishGenericConnection

public override async Task<HttpRequestData> HandleRequestAsync(HttpStatusCode statusCode = HttpStatusCode.OK, IList<HttpHeaderData> headers = null, string content = "")
{
using (GenericLoopbackConnection connection = await EstablishGenericConnectionAsync().ConfigureAwait(false))
await using (GenericLoopbackConnection connection = await EstablishGenericConnectionAsync().ConfigureAwait(false))
{
return await connection.HandleRequestAsync(statusCode, headers, content).ConfigureAwait(false);
}
}

public override async Task AcceptConnectionAsync(Func<GenericLoopbackConnection, Task> funcAsync)
{
using (GenericLoopbackConnection connection = await EstablishGenericConnectionAsync().ConfigureAwait(false))
await using (GenericLoopbackConnection connection = await EstablishGenericConnectionAsync().ConfigureAwait(false))
{
await funcAsync(connection).ConfigureAwait(false);
}
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -717,7 +717,7 @@ await LoopbackServer.CreateClientAndServerAsync(
Assert.Equal(0, requestData.GetHeaderValueCount("Authorization"));

// Establish a session connection
using var connection = await server.EstablishConnectionAsync();
await using LoopbackServer.Connection connection = await server.EstablishConnectionAsync();
requestData = await connection.ReadRequestDataAsync();
string authHeaderValue = requestData.GetSingleHeaderValue("Authorization");
Assert.Contains("NTLM", authHeaderValue);
Expand Down
11 changes: 8 additions & 3 deletions src/libraries/Common/tests/System/Net/Http/LoopbackServer.cs
Original file line numberDiff line numberDiff line change
Expand Up@@ -156,7 +156,7 @@ public async Task<Connection> EstablishConnectionAsync()

public async Task AcceptConnectionAsync(Func<Connection, Task> funcAsync)
{
using (Connection connection = await EstablishConnectionAsync().ConfigureAwait(false))
await using (Connection connection = await EstablishConnectionAsync().ConfigureAwait(false))
{
await funcAsync(connection).ConfigureAwait(false);
}
Expand DownExpand Up@@ -654,7 +654,7 @@ private async Task<byte[]> ReadLineBytesAsync()
return null;
}

public override void Dispose()
public override async ValueTask DisposeAsync()
{
try
{
Expand All@@ -666,7 +666,12 @@ public override void Dispose()
}
catch (Exception) { }

#if !NETSTANDARD2_0 && !NETFRAMEWORK
await _stream.DisposeAsync().ConfigureAwait(false);
#else
_stream.Dispose();
await Task.CompletedTask.ConfigureAwait(false);
#endif
_socket?.Dispose();
}

Expand DownExpand Up@@ -1076,7 +1081,7 @@ public override Task WaitForCloseAsync(CancellationToken cancellationToken)

public override async Task<HttpRequestData> HandleRequestAsync(HttpStatusCode statusCode = HttpStatusCode.OK, IList<HttpHeaderData> headers = null, string content = "")
{
using (Connection connection = await EstablishConnectionAsync().ConfigureAwait(false))
await using (Connection connection = await EstablishConnectionAsync().ConfigureAwait(false))
{
return await connection.HandleRequestAsync(statusCode, headers, content).ConfigureAwait(false);
}
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -14,9 +14,8 @@
</PropertyGroup>

<ItemGroup>
<!-- Requires Private=true to calculate ReferenceCopyLocalPaths items. Also share System.Net.Quic which isn't part of aspnetcore's shared framework but which is needed by them. -->
<ProjectReference Include="@(AspNetCoreAppLibrary->'$(LibrariesProjectRoot)%(Identity)\src\%(Identity).csproj');
$(LibrariesProjectRoot)System.Net.Quic\src\System.Net.Quic.csproj"
<!-- Requires Private=true to calculate ReferenceCopyLocalPaths items. -->
<ProjectReference Include="@(AspNetCoreAppLibrary->'$(LibrariesProjectRoot)%(Identity)\src\%(Identity).csproj')"
Pack="true"
PrivateAssets="all"
Private="true"
Expand Down
1 change: 0 additions & 1 deletion src/libraries/NetCoreAppLibrary.props
Original file line numberDiff line numberDiff line change
Expand Up@@ -175,7 +175,6 @@
System.Xml.XPath.XDocument;
</NetCoreAppLibrary>
<NetCoreAppLibraryNoReference>
System.Net.Quic;
System.Private.CoreLib;
System.Private.DataContractSerialization;
System.Private.Uri;
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -41,7 +41,7 @@ await LoopbackServer.CreateClientAndServerAsync(
},
async s =>
{
using (LoopbackServer.Connection connection = await s.EstablishConnectionAsync().ConfigureAwait(false))
await using (LoopbackServer.Connection connection = await s.EstablishConnectionAsync().ConfigureAwait(false))
{
SslStream sslStream = connection.Stream as SslStream;
Assert.NotNull(sslStream);
Expand DownExpand Up@@ -76,7 +76,7 @@ await Http2LoopbackServer.CreateClientAndServerAsync(
},
async s =>
{
using (Http2LoopbackConnection connection = await s.EstablishConnectionAsync().ConfigureAwait(false))
await using (Http2LoopbackConnection connection = await s.EstablishConnectionAsync().ConfigureAwait(false))
{
SslStream sslStream = connection.Stream as SslStream;
Assert.NotNull(sslStream);
Expand Down
Loading