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 #53201

Closed
wants to merge 9 commits into from
Closed
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);

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,53 @@ public Task<HttpRequestData> AcceptConnectionSendResponseAndCloseAsync(HttpStatu
}
}

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

public SocketWrapper(Socket socket)
{
this._socket = socket; _websocket = null;
}
public SocketWrapper(WebSocket websocket)
{
this._socket = null; _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);
Task.WaitAll(task);
}
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 @@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ await LoopbackServerFactory.CreateClientAndServerAsync(

[Theory]
[MemberData(nameof(CookieNamesValuesAndUseCookies))]
[SkipOnPlatform(TestPlatforms.Browser, "CookieContainer is not supported on Browser")]
public async Task GetAsync_SetCookieContainer_CookieSent(string cookieName, string cookieValue, bool useCookies)
{
await LoopbackServerFactory.CreateClientAndServerAsync(
Expand Down Expand Up @@ -92,6 +93,7 @@ await LoopbackServerFactory.CreateClientAndServerAsync(
}

[Fact]
[SkipOnPlatform(TestPlatforms.Browser, "CookieContainer is not supported on Browser")]
public async Task GetAsync_SetCookieContainerMultipleCookies_CookiesSent()
{
var cookies = new Cookie[]
Expand Down Expand Up @@ -211,6 +213,7 @@ private string GetCookieValue(HttpRequestData request)
}

[Fact]
[SkipOnPlatform(TestPlatforms.Browser, "CookieContainer is not supported on Browser")]
public async Task GetAsync_SetCookieContainerAndCookieHeader_BothCookiesSent()
{
await LoopbackServerFactory.CreateServerAsync(async (server, url) =>
Expand Down Expand Up @@ -238,6 +241,7 @@ await LoopbackServerFactory.CreateServerAsync(async (server, url) =>
}

[Fact]
[SkipOnPlatform(TestPlatforms.Browser, "CookieContainer is not supported on Browser")]
public async Task GetAsync_SetCookieContainerAndMultipleCookieHeaders_BothCookiesSent()
{
await LoopbackServerFactory.CreateServerAsync(async (server, url) =>
Expand Down Expand Up @@ -289,6 +293,7 @@ await LoopbackServerFactory.CreateServerAsync(async (server, url) =>
}

[Fact]
[SkipOnPlatform(TestPlatforms.Browser, "CookieContainer is not supported on Browser")]
public async Task GetAsyncWithRedirect_SetCookieContainer_CorrectCookiesSent()
{
const string path1 = "/foo";
Expand Down Expand Up @@ -329,6 +334,7 @@ await LoopbackServerFactory.CreateClientAndServerAsync(async url =>

[Theory]
[MemberData(nameof(CookieNamesValuesAndUseCookies))]
[SkipOnPlatform(TestPlatforms.Browser, "CookieContainer is not supported on Browser")]
public async Task GetAsync_ReceiveSetCookieHeader_CookieAdded(string cookieName, string cookieValue, bool useCookies)
{
await LoopbackServerFactory.CreateServerAsync(async (server, url) =>
Expand Down Expand Up @@ -360,6 +366,7 @@ await LoopbackServerFactory.CreateServerAsync(async (server, url) =>
}

[Fact]
[SkipOnPlatform(TestPlatforms.Browser, "CookieContainer is not supported on Browser")]
public async Task GetAsync_ReceiveMultipleSetCookieHeaders_CookieAdded()
{
await LoopbackServerFactory.CreateServerAsync(async (server, url) =>
Expand Down Expand Up @@ -399,6 +406,7 @@ await LoopbackServerFactory.CreateServerAsync(async (server, url) =>
// the cookie should be added with Path=/path.
// ConditionalFact: CookieContainer does not follow RFC6265 on .NET Framework, therefore the (WinHttpHandler) test is expected to fail
[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotNetFramework))]
[SkipOnPlatform(TestPlatforms.Browser, "CookieContainer is not supported on Browser")]
public async Task GetAsync_NoPathDefined_CookieAddedWithDefaultPath()
{
await LoopbackServerFactory.CreateServerAsync(async (server, serverUrl) =>
Expand Down Expand Up @@ -428,6 +436,7 @@ await LoopbackServerFactory.CreateServerAsync(async (server, serverUrl) =>
// these cookies should be accepted by the client.
// ConditionalFact: CookieContainer does not follow RFC6265 on .NET Framework, therefore the (WinHttpHandler) test is expected to fail
[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotNetFramework))]
[SkipOnPlatform(TestPlatforms.Browser, "CookieContainer is not supported on Browser")]
public async Task GetAsync_CookiePathDoesNotMatchRequestPath_CookieAccepted()
{
await LoopbackServerFactory.CreateServerAsync(async (server, serverUrl) =>
Expand Down Expand Up @@ -459,6 +468,7 @@ await LoopbackServerFactory.CreateServerAsync(async (server, serverUrl) =>
// https://github.com/dotnet/runtime/issues/26141#issuecomment-612097147
// ConditionalFact: CookieContainer does not follow RFC6265 on .NET Framework, therefore the (WinHttpHandler) test is expected to fail
[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotNetFramework))]
[SkipOnPlatform(TestPlatforms.Browser, "CookieContainer is not supported on Browser")]
public async Task GetAsync_Redirect_CookiesArePreserved()
{
HttpClientHandler handler = CreateHttpClientHandler();
Expand Down Expand Up @@ -501,6 +511,7 @@ await LoopbackServerFactory.CreateClientAndServerAsync(async serverUrl =>
}

[Fact]
[SkipOnPlatform(TestPlatforms.Browser, "CookieContainer is not supported on Browser")]
public async Task GetAsync_ReceiveSetCookieHeader_CookieUpdated()
{
const string newCookieValue = "789";
Expand Down Expand Up @@ -528,6 +539,7 @@ await LoopbackServerFactory.CreateServerAsync(async (server, url) =>
}

[Fact]
[SkipOnPlatform(TestPlatforms.Browser, "CookieContainer is not supported on Browser")]
public async Task GetAsync_ReceiveSetCookieHeader_CookieRemoved()
{
await LoopbackServerFactory.CreateServerAsync(async (server, url) =>
Expand All @@ -551,6 +563,7 @@ await LoopbackServerFactory.CreateServerAsync(async (server, url) =>
}

[Fact]
[SkipOnPlatform(TestPlatforms.Browser, "CookieContainer is not supported on Browser")]
public async Task GetAsync_ReceiveInvalidSetCookieHeader_ValidCookiesAdded()
{
await LoopbackServerFactory.CreateServerAsync(async (server, url) =>
Expand Down Expand Up @@ -585,6 +598,7 @@ await LoopbackServerFactory.CreateServerAsync(async (server, url) =>
}

[Fact]
[SkipOnPlatform(TestPlatforms.Browser, "CookieContainer is not supported on Browser")]
public async Task GetAsyncWithRedirect_ReceiveSetCookie_CookieSent()
{
const string path1 = "/foo";
Expand Down Expand Up @@ -638,6 +652,7 @@ await LoopbackServerFactory.CreateClientAndServerAsync(async url =>
}

[Fact]
[SkipOnPlatform(TestPlatforms.Browser, "CookieContainer is not supported on Browser")]
public async Task GetAsyncWithBasicAuth_ReceiveSetCookie_CookieSent()
{
if (IsWinHttpHandler)
Expand Down Expand Up @@ -757,6 +772,7 @@ public abstract class HttpClientHandlerTest_Cookies_Http11 : HttpClientHandlerTe
public HttpClientHandlerTest_Cookies_Http11(ITestOutputHelper output) : base(output) { }

[Fact]
[SkipOnPlatform(TestPlatforms.Browser, "CookieContainer is not supported on Browser")]
public async Task GetAsync_ReceiveMultipleSetCookieHeaders_CookieAdded()
{
await LoopbackServer.CreateServerAsync(async (server, url) =>
Expand Down
Loading