Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP][wasm][testing] remote loop network tests via xharness and websocket #54289

Merged
merged 12 commits into from
Jun 22, 2021
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
4 changes: 4 additions & 0 deletions src/libraries/Common/tests/System/Net/Configuration.Http.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,15 @@ public static partial class Http
public static string EchoClientCertificateRemoteServer => GetValue("DOTNET_TEST_HTTPHOST_ECHOCLIENTCERT", "https://corefx-net-tls.azurewebsites.net/EchoClientCertificate.ashx");
public static string Http2ForceUnencryptedLoopback => GetValue("DOTNET_TEST_HTTP2_FORCEUNENCRYPTEDLOOPBACK");

public static string RemoteLoopHost => GetValue("DOTNET_TEST_REMOTE_LOOP_HOST");

private const string EchoHandler = "Echo.ashx";
private const string EmptyContentHandler = "EmptyContent.ashx";
private const string RedirectHandler = "Redirect.ashx";
private const string VerifyUploadHandler = "VerifyUpload.ashx";
private const string DeflateHandler = "Deflate.ashx";
private const string GZipHandler = "GZip.ashx";
private const string RemoteLoopHandler = "RemoteLoop";

public static readonly Uri RemoteEchoServer = new Uri("http://" + Host + "/" + EchoHandler);
public static readonly Uri SecureRemoteEchoServer = new Uri("https://" + SecureHost + "/" + EchoHandler);
Expand All @@ -67,6 +70,7 @@ public static partial class Http
public static readonly Uri RemoteGZipServer = new Uri("http://" + Host + "/" + GZipHandler);
public static readonly Uri Http2RemoteDeflateServer = new Uri("https://" + Http2Host + "/" + DeflateHandler);
public static readonly Uri Http2RemoteGZipServer = new Uri("https://" + Http2Host + "/" + GZipHandler);
public static Uri RemoteLoopServer => new Uri("ws://" + RemoteLoopHost + "/" + RemoteLoopHandler);
pavelsavara marked this conversation as resolved.
Show resolved Hide resolved

public static readonly object[][] EchoServers = EchoServerList.Select(x => new object[] { x }).ToArray();
public static readonly object[][] VerifyUploadServers = { new object[] { RemoteVerifyUploadServer }, new object[] { SecureRemoteVerifyUploadServer }, new object[] { Http2RemoteVerifyUploadServer } };
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
using System.Security.Cryptography.X509Certificates;
using System.IO;
using System.Net.Sockets;
using System.Net.WebSockets;
using System.Threading;

namespace System.Net.Test.Common
{
Expand All @@ -20,7 +22,7 @@ public abstract class LoopbackServerFactory
public abstract GenericLoopbackServer CreateServer(GenericLoopbackOptions options = null);
public abstract Task CreateServerAsync(Func<GenericLoopbackServer, Uri, Task> funcAsync, int millisecondsTimeout = 60_000, GenericLoopbackOptions options = null);

public abstract Task<GenericLoopbackConnection> CreateConnectionAsync(Socket socket, Stream stream, GenericLoopbackOptions options = null);
public abstract Task<GenericLoopbackConnection> CreateConnectionAsync(SocketWrapper socket, Stream stream, GenericLoopbackOptions options = null);

public abstract Version Version { get; }

Expand Down Expand Up @@ -59,6 +61,54 @@ public Task<HttpRequestData> AcceptConnectionSendResponseAndCloseAsync(HttpStatu
}
}

public sealed class SocketWrapper : IDisposable
{
private Socket _socket;
private WebSocket _websocket;

public SocketWrapper(Socket socket)
{
_socket = socket;
}
public SocketWrapper(WebSocket websocket)
{
_websocket = websocket;
}

public void Dispose()
{
_socket?.Dispose();
_websocket?.Dispose();
}
public void Close()
{
_socket?.Close();
CloseWebSocket();
}

public void Shutdown(SocketShutdown how)
{
_socket?.Shutdown(how);
CloseWebSocket();
}

private void CloseWebSocket()
{
if (_websocket != null && (_websocket.State == WebSocketState.Open || _websocket.State == WebSocketState.Connecting || _websocket.State == WebSocketState.None))
{
try
{
var task = _websocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "closing remoteLoop", CancellationToken.None);
// Block and wait for the task to complete synchronously
Task.WaitAll(task);
pavelsavara marked this conversation as resolved.
Show resolved Hide resolved
}
catch (Exception)
{
}
}
}
}

public abstract class GenericLoopbackConnection : IDisposable
{
public abstract void Dispose();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public class Http2LoopbackConnection : GenericLoopbackConnection
{
public const string Http2Prefix = "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n";

private Socket _connectionSocket;
private SocketWrapper _connectionSocket;
private Stream _connectionStream;
private TaskCompletionSource<bool> _ignoredSettingsAckPromise;
private bool _ignoreWindowUpdates;
Expand All @@ -34,19 +34,19 @@ public class Http2LoopbackConnection : GenericLoopbackConnection
public Stream Stream => _connectionStream;
public Task<bool> SettingAckWaiter => _ignoredSettingsAckPromise?.Task;

private Http2LoopbackConnection(Socket socket, Stream stream, TimeSpan timeout)
private Http2LoopbackConnection(SocketWrapper socket, Stream stream, TimeSpan timeout)
{
_connectionSocket = socket;
_connectionStream = stream;
_timeout = timeout;
}

public static Task<Http2LoopbackConnection> CreateAsync(Socket socket, Stream stream, Http2Options httpOptions)
public static Task<Http2LoopbackConnection> CreateAsync(SocketWrapper socket, Stream stream, Http2Options httpOptions)
{
return CreateAsync(socket, stream, httpOptions, Http2LoopbackServer.Timeout);
}

public static async Task<Http2LoopbackConnection> CreateAsync(Socket socket, Stream stream, Http2Options httpOptions, TimeSpan timeout)
public static async Task<Http2LoopbackConnection> CreateAsync(SocketWrapper socket, Stream stream, Http2Options httpOptions, TimeSpan timeout)
{
if (httpOptions.UseSsl)
{
Expand Down Expand Up @@ -230,9 +230,9 @@ private async Task<Frame> ReadFrameAsync(CancellationToken cancellationToken)
}

// Reset and return underlying networking objects.
public (Socket, Stream) ResetNetwork()
public (SocketWrapper, Stream) ResetNetwork()
{
Socket oldSocket = _connectionSocket;
SocketWrapper oldSocket = _connectionSocket;
Stream oldStream = _connectionStream;
_connectionSocket = null;
_connectionStream = null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,10 @@ public async Task<Http2LoopbackConnection> AcceptConnectionAsync(TimeSpan? timeo
Socket connectionSocket = await _listenSocket.AcceptAsync().ConfigureAwait(false);

var stream = new NetworkStream(connectionSocket, ownsSocket: true);
var wrapper = new SocketWrapper(connectionSocket);
Http2LoopbackConnection connection =
timeout != null ? await Http2LoopbackConnection.CreateAsync(connectionSocket, stream, _options, timeout.Value).ConfigureAwait(false) :
await Http2LoopbackConnection.CreateAsync(connectionSocket, stream, _options).ConfigureAwait(false);
timeout != null ? await Http2LoopbackConnection.CreateAsync(wrapper, stream, _options, timeout.Value).ConfigureAwait(false) :
await Http2LoopbackConnection.CreateAsync(wrapper, stream, _options).ConfigureAwait(false);
_connections.Add(connection);

return connection;
Expand Down Expand Up @@ -201,7 +202,7 @@ public override GenericLoopbackServer CreateServer(GenericLoopbackOptions option
return Http2LoopbackServer.CreateServer(CreateOptions(options));
}

public override async Task<GenericLoopbackConnection> CreateConnectionAsync(Socket socket, Stream stream, GenericLoopbackOptions options = null)
public override async Task<GenericLoopbackConnection> CreateConnectionAsync(SocketWrapper socket, Stream stream, GenericLoopbackOptions options = null)
{
return await Http2LoopbackConnection.CreateAsync(socket, stream, CreateOptions(options)).ConfigureAwait(false);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ public override async Task CreateServerAsync(Func<GenericLoopbackServer, Uri, Ta
await funcAsync(server, server.Address).WaitAsync(TimeSpan.FromMilliseconds(millisecondsTimeout));
}

public override Task<GenericLoopbackConnection> CreateConnectionAsync(Socket socket, Stream stream, GenericLoopbackOptions options = null)
public override Task<GenericLoopbackConnection> CreateConnectionAsync(SocketWrapper socket, Stream stream, GenericLoopbackOptions options = null)
{
// TODO: make a new overload that takes a MultiplexedConnection.
// This method is always unacceptable to call for HTTP/3.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,13 +87,13 @@ public override async Task<GenericLoopbackConnection> EstablishGenericConnection
if (sslStream.NegotiatedApplicationProtocol == SslApplicationProtocol.Http2)
{
// Do not pass original options so the CreateConnectionAsync won't try to do ALPN again.
return connection = await Http2LoopbackServerFactory.Singleton.CreateConnectionAsync(socket, stream, options).ConfigureAwait(false);
return connection = await Http2LoopbackServerFactory.Singleton.CreateConnectionAsync(new SocketWrapper(socket), stream, options).ConfigureAwait(false);
}
if (sslStream.NegotiatedApplicationProtocol == SslApplicationProtocol.Http11 ||
sslStream.NegotiatedApplicationProtocol == default)
{
// Do not pass original options so the CreateConnectionAsync won't try to do ALPN again.
return connection = await Http11LoopbackServerFactory.Singleton.CreateConnectionAsync(socket, stream, options).ConfigureAwait(false);
return connection = await Http11LoopbackServerFactory.Singleton.CreateConnectionAsync(new SocketWrapper(socket), stream, options).ConfigureAwait(false);
}
else
{
Expand All @@ -103,11 +103,11 @@ public override async Task<GenericLoopbackConnection> EstablishGenericConnection

if (_options.ClearTextVersion == HttpVersion.Version11)
{
return connection = await Http11LoopbackServerFactory.Singleton.CreateConnectionAsync(socket, stream, options).ConfigureAwait(false);
return connection = await Http11LoopbackServerFactory.Singleton.CreateConnectionAsync(new SocketWrapper(socket), stream, options).ConfigureAwait(false);
}
else if (_options.ClearTextVersion == HttpVersion.Version20)
{
return connection = await Http2LoopbackServerFactory.Singleton.CreateConnectionAsync(socket, stream, options).ConfigureAwait(false);
return connection = await Http2LoopbackServerFactory.Singleton.CreateConnectionAsync(new SocketWrapper(socket), stream, options).ConfigureAwait(false);
}
else
{
Expand Down Expand Up @@ -187,7 +187,7 @@ public override GenericLoopbackServer CreateServer(GenericLoopbackOptions option
return HttpAgnosticLoopbackServer.CreateServer(CreateOptions(options));
}

public override Task<GenericLoopbackConnection> CreateConnectionAsync(Socket socket, Stream stream, GenericLoopbackOptions options = null)
public override Task<GenericLoopbackConnection> CreateConnectionAsync(SocketWrapper socket, Stream stream, GenericLoopbackOptions options = null)
{
// This method is always unacceptable to call for an agnostic server.
throw new NotImplementedException("HttpAgnosticLoopbackServerFactory cannot create connection.");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,6 @@ public static IEnumerable<object[]> Authentication_SocketsHttpHandler_TestData()

[Theory]
[MemberData(nameof(Authentication_TestData))]
[ActiveIssue("https://github.com/dotnet/runtime/issues/39187", TestPlatforms.Browser)]
public async Task HttpClientHandler_Authentication_Succeeds(string authenticateHeader, bool result)
{
if (PlatformDetection.IsWindowsNanoServer)
Expand Down Expand Up @@ -144,7 +143,6 @@ public async Task HttpClientHandler_MultipleAuthenticateHeaders_WithSameAuth_Suc
[Theory]
[InlineData("WWW-Authenticate: Basic realm=\"hello\"\r\nWWW-Authenticate: Digest realm=\"hello\", nonce=\"hello\", algorithm=MD5\r\n")]
[InlineData("WWW-Authenticate: Digest realm=\"hello\", nonce=\"hello\", algorithm=MD5\r\nWWW-Authenticate: Basic realm=\"hello\"\r\n")]
[ActiveIssue("https://github.com/dotnet/runtime/issues/39187", TestPlatforms.Browser)]
public async Task HttpClientHandler_MultipleAuthenticateHeaders_Succeeds(string authenticateHeader)
{
if (PlatformDetection.IsWindowsNanoServer)
Expand All @@ -164,7 +162,6 @@ await LoopbackServer.CreateServerAsync(async (server, url) =>
[Theory]
[InlineData("WWW-Authenticate: Basic realm=\"hello\"\r\nWWW-Authenticate: NTLM\r\n", "Basic", "Negotiate")]
[InlineData("WWW-Authenticate: Basic realm=\"hello\"\r\nWWW-Authenticate: Digest realm=\"hello\", nonce=\"hello\", algorithm=MD5\r\nWWW-Authenticate: NTLM\r\n", "Digest", "Negotiate")]
[ActiveIssue("https://github.com/dotnet/runtime/issues/39187", TestPlatforms.Browser)]
public async Task HttpClientHandler_MultipleAuthenticateHeaders_PicksSupported(string authenticateHeader, string supportedAuth, string unsupportedAuth)
{
if (PlatformDetection.IsWindowsNanoServer)
Expand All @@ -190,7 +187,6 @@ await LoopbackServer.CreateServerAsync(async (server, url) =>
[Theory]
[InlineData("WWW-Authenticate: Basic realm=\"hello\"\r\n")]
[InlineData("WWW-Authenticate: Digest realm=\"hello\", nonce=\"testnonce\"\r\n")]
[ActiveIssue("https://github.com/dotnet/runtime/issues/39187", TestPlatforms.Browser)]
public async Task HttpClientHandler_IncorrectCredentials_Fails(string authenticateHeader)
{
var options = new LoopbackServer.Options { Domain = Domain, Username = Username, Password = Password };
Expand Down Expand Up @@ -228,7 +224,6 @@ public static IEnumerable<object[]> Authentication_TestData()
[InlineData("NTLM")]
[InlineData("Kerberos")]
[InlineData("Negotiate")]
[ActiveIssue("https://github.com/dotnet/runtime/issues/39187", TestPlatforms.Browser)]
public async Task PreAuthenticate_NoPreviousAuthenticatedRequests_NoCredentialsSent(string credCacheScheme)
{
const int NumRequests = 3;
Expand Down Expand Up @@ -271,7 +266,6 @@ await LoopbackServer.CreateClientAndServerAsync(async uri =>
[Theory]
[InlineData(null, "WWW-Authenticate: Basic realm=\"hello\"\r\n")]
[InlineData("Basic", "WWW-Authenticate: Basic realm=\"hello\"\r\n")]
[ActiveIssue("https://github.com/dotnet/runtime/issues/39187", TestPlatforms.Browser)]
public async Task PreAuthenticate_FirstRequestNoHeaderAndAuthenticates_SecondRequestPreauthenticates(string credCacheScheme, string authResponse)
{
await LoopbackServer.CreateClientAndServerAsync(async uri =>
Expand Down Expand Up @@ -364,7 +358,6 @@ await LoopbackServer.CreateClientAndServerAsync(async uri =>
[InlineData((HttpStatusCode)508)] // LoopDetected
[InlineData((HttpStatusCode)510)] // NotExtended
[InlineData((HttpStatusCode)511)] // NetworkAuthenticationRequired
[ActiveIssue("https://github.com/dotnet/runtime/issues/39187", TestPlatforms.Browser)]
public async Task PreAuthenticate_FirstRequestNoHeader_SecondRequestVariousStatusCodes_ThirdRequestPreauthenticates(HttpStatusCode statusCode)
{
const string AuthResponse = "WWW-Authenticate: Basic realm=\"hello\"\r\n";
Expand Down Expand Up @@ -408,7 +401,6 @@ await LoopbackServer.CreateClientAndServerAsync(async uri =>
[InlineData("/something/hello.html", "/world.html", false)]
[InlineData("/something/hello.html", "/another/", false)]
[InlineData("/something/hello.html", "/another/hello.html", false)]
[ActiveIssue("https://github.com/dotnet/runtime/issues/39187", TestPlatforms.Browser)]
public async Task PreAuthenticate_AuthenticatedUrl_ThenTryDifferentUrl_SendsAuthHeaderOnlyIfPrefixMatches(
string originalRelativeUri, string secondRelativeUri, bool expectedAuthHeader)
{
Expand Down Expand Up @@ -448,7 +440,6 @@ await LoopbackServer.CreateClientAndServerAsync(async uri =>
}

[Fact]
[ActiveIssue("https://github.com/dotnet/runtime/issues/39187", TestPlatforms.Browser)]
public async Task PreAuthenticate_SuccessfulBasicButThenFails_DoesntLoopInfinitely()
{
await LoopbackServer.CreateClientAndServerAsync(async uri =>
Expand Down Expand Up @@ -487,7 +478,6 @@ await LoopbackServer.CreateClientAndServerAsync(async uri =>
}

[Fact]
[ActiveIssue("https://github.com/dotnet/runtime/issues/39187", TestPlatforms.Browser)]
public async Task PreAuthenticate_SuccessfulBasic_ThenDigestChallenged()
{
if (IsWinHttpHandler)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,7 @@ await LoopbackServerFactory.CreateServerAsync(async (server, url) =>
}

[Fact]
[SkipOnPlatform(TestPlatforms.Browser, "MaxConnectionsPerServer is not supported on Browser")]
public async Task MaxConnectionsPerServer_WaitingConnectionsAreCancelable()
{
if (LoopbackServerFactory.Version >= HttpVersion20.Value)
Expand Down
Loading