diff --git a/src/libraries/Common/tests/System/Net/Configuration.Http.cs b/src/libraries/Common/tests/System/Net/Configuration.Http.cs index e43c2c0e385e9..ae1481c56061c 100644 --- a/src/libraries/Common/tests/System/Net/Configuration.Http.cs +++ b/src/libraries/Common/tests/System/Net/Configuration.Http.cs @@ -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); @@ -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 } }; diff --git a/src/libraries/Common/tests/System/Net/Http/GenericLoopbackServer.cs b/src/libraries/Common/tests/System/Net/Http/GenericLoopbackServer.cs index d3095bd7a2045..c145b6aa3d493 100644 --- a/src/libraries/Common/tests/System/Net/Http/GenericLoopbackServer.cs +++ b/src/libraries/Common/tests/System/Net/Http/GenericLoopbackServer.cs @@ -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 { @@ -20,7 +22,7 @@ public abstract class LoopbackServerFactory public abstract GenericLoopbackServer CreateServer(GenericLoopbackOptions options = null); public abstract Task CreateServerAsync(Func funcAsync, int millisecondsTimeout = 60_000, GenericLoopbackOptions options = null); - public abstract Task CreateConnectionAsync(Socket socket, Stream stream, GenericLoopbackOptions options = null); + public abstract Task CreateConnectionAsync(SocketWrapper socket, Stream stream, GenericLoopbackOptions options = null); public abstract Version Version { get; } @@ -59,6 +61,54 @@ public Task 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); + } + catch (Exception) + { + } + } + } + } + public abstract class GenericLoopbackConnection : IDisposable { public abstract void Dispose(); diff --git a/src/libraries/Common/tests/System/Net/Http/Http2LoopbackConnection.cs b/src/libraries/Common/tests/System/Net/Http/Http2LoopbackConnection.cs index 01fa9d4e697b5..5dcbc2d3863e3 100644 --- a/src/libraries/Common/tests/System/Net/Http/Http2LoopbackConnection.cs +++ b/src/libraries/Common/tests/System/Net/Http/Http2LoopbackConnection.cs @@ -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 _ignoredSettingsAckPromise; private bool _ignoreWindowUpdates; @@ -34,19 +34,19 @@ public class Http2LoopbackConnection : GenericLoopbackConnection public Stream Stream => _connectionStream; public Task 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 CreateAsync(Socket socket, Stream stream, Http2Options httpOptions) + public static Task CreateAsync(SocketWrapper socket, Stream stream, Http2Options httpOptions) { return CreateAsync(socket, stream, httpOptions, Http2LoopbackServer.Timeout); } - public static async Task CreateAsync(Socket socket, Stream stream, Http2Options httpOptions, TimeSpan timeout) + public static async Task CreateAsync(SocketWrapper socket, Stream stream, Http2Options httpOptions, TimeSpan timeout) { if (httpOptions.UseSsl) { @@ -230,9 +230,9 @@ private async Task 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; diff --git a/src/libraries/Common/tests/System/Net/Http/Http2LoopbackServer.cs b/src/libraries/Common/tests/System/Net/Http/Http2LoopbackServer.cs index 45c2edf345951..45df14c0380ea 100644 --- a/src/libraries/Common/tests/System/Net/Http/Http2LoopbackServer.cs +++ b/src/libraries/Common/tests/System/Net/Http/Http2LoopbackServer.cs @@ -91,9 +91,10 @@ public async Task 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; @@ -201,7 +202,7 @@ public override GenericLoopbackServer CreateServer(GenericLoopbackOptions option return Http2LoopbackServer.CreateServer(CreateOptions(options)); } - public override async Task CreateConnectionAsync(Socket socket, Stream stream, GenericLoopbackOptions options = null) + public override async Task CreateConnectionAsync(SocketWrapper socket, Stream stream, GenericLoopbackOptions options = null) { return await Http2LoopbackConnection.CreateAsync(socket, stream, CreateOptions(options)).ConfigureAwait(false); } diff --git a/src/libraries/Common/tests/System/Net/Http/Http3LoopbackServer.cs b/src/libraries/Common/tests/System/Net/Http/Http3LoopbackServer.cs index cf83b893ff739..b84393a88b1d8 100644 --- a/src/libraries/Common/tests/System/Net/Http/Http3LoopbackServer.cs +++ b/src/libraries/Common/tests/System/Net/Http/Http3LoopbackServer.cs @@ -97,7 +97,7 @@ public override async Task CreateServerAsync(Func CreateConnectionAsync(Socket socket, Stream stream, GenericLoopbackOptions options = null) + public override Task 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. diff --git a/src/libraries/Common/tests/System/Net/Http/HttpAgnosticLoopbackServer.cs b/src/libraries/Common/tests/System/Net/Http/HttpAgnosticLoopbackServer.cs index ae436df429a1d..88a8071153e6c 100644 --- a/src/libraries/Common/tests/System/Net/Http/HttpAgnosticLoopbackServer.cs +++ b/src/libraries/Common/tests/System/Net/Http/HttpAgnosticLoopbackServer.cs @@ -87,13 +87,13 @@ public override async Task 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 { @@ -103,11 +103,11 @@ public override async Task 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 { @@ -187,7 +187,7 @@ public override GenericLoopbackServer CreateServer(GenericLoopbackOptions option return HttpAgnosticLoopbackServer.CreateServer(CreateOptions(options)); } - public override Task CreateConnectionAsync(Socket socket, Stream stream, GenericLoopbackOptions options = null) + public override Task 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."); diff --git a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Authentication.cs b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Authentication.cs index 4df4100a8ed41..f7ccc3127e9ab 100644 --- a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Authentication.cs +++ b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Authentication.cs @@ -104,7 +104,6 @@ public static IEnumerable 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) @@ -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) @@ -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) @@ -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 }; @@ -228,7 +224,6 @@ public static IEnumerable 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; @@ -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 => @@ -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"; @@ -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) { @@ -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 => @@ -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) diff --git a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Cancellation.cs b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Cancellation.cs index d246ca53e9303..410d2a6987b60 100644 --- a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Cancellation.cs +++ b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Cancellation.cs @@ -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) diff --git a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Cookies.cs b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Cookies.cs index e722e8bb37c51..dbb1382c9aaf5 100644 --- a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Cookies.cs +++ b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Cookies.cs @@ -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( @@ -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[] @@ -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) => @@ -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) => @@ -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"; @@ -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) => @@ -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) => @@ -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) => @@ -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) => @@ -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(); @@ -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"; @@ -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) => @@ -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) => @@ -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"; @@ -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) @@ -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) => diff --git a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Decompression.cs b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Decompression.cs index 6cf46633cc69b..f53b6fcb910f8 100644 --- a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Decompression.cs +++ b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Decompression.cs @@ -46,7 +46,7 @@ public static IEnumerable RemoteServersAndCompressionUris() [InlineData("deflate", true)] [InlineData("br", false)] [InlineData("br", true)] - [ActiveIssue("https://github.com/dotnet/runtime/issues/39187", TestPlatforms.Browser)] + [SkipOnPlatform(TestPlatforms.Browser, "AutomaticDecompression not supported on Browser")] public async Task DecompressedResponse_MethodSpecified_DecompressedContentReturned(string encodingName, bool all) { Func compress; @@ -136,7 +136,7 @@ public static IEnumerable DecompressedResponse_MethodNotSpecified_Orig [Theory] [MemberData(nameof(DecompressedResponse_MethodNotSpecified_OriginalContentReturned_MemberData))] - [ActiveIssue("https://github.com/dotnet/runtime/issues/39187", TestPlatforms.Browser)] + [SkipOnPlatform(TestPlatforms.Browser, "AutomaticDecompression not supported on Browser")] public async Task DecompressedResponse_MethodNotSpecified_OriginalContentReturned( string encodingName, Func compress, DecompressionMethods methods) { @@ -263,7 +263,7 @@ public async Task GetAsync_SetAutomaticDecompression_HeadersRemoved(Configuratio [InlineData(DecompressionMethods.Deflate, "deflate", "gzip")] [InlineData(DecompressionMethods.Deflate, "deflate", "br")] [InlineData(DecompressionMethods.GZip | DecompressionMethods.Deflate, "gzip, deflate", "gzip, deflate")] - [ActiveIssue("https://github.com/dotnet/runtime/issues/39187", TestPlatforms.Browser)] + [SkipOnPlatform(TestPlatforms.Browser, "AutomaticDecompression not supported on Browser")] public async Task GetAsync_SetAutomaticDecompression_AcceptEncodingHeaderSentWithNoDuplicates( DecompressionMethods methods, string encodings, @@ -316,7 +316,7 @@ await LoopbackServer.CreateServerAsync(async (server, url) => #endif [InlineData(DecompressionMethods.GZip | DecompressionMethods.Deflate, "gzip; q=1.0, deflate; q=1.0", "")] [InlineData(DecompressionMethods.GZip | DecompressionMethods.Deflate, "gzip; q=1.0", "deflate")] - [ActiveIssue("https://github.com/dotnet/runtime/issues/39187", TestPlatforms.Browser)] + [SkipOnPlatform(TestPlatforms.Browser, "AutomaticDecompression not supported on Browser")] public async Task GetAsync_SetAutomaticDecompression_AcceptEncodingHeaderSentWithQualityWeightingsNoDuplicates( DecompressionMethods methods, string manualAcceptEncodingHeaderValues, diff --git a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.cs b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.cs index 06e80b66b00be..33392864210a8 100644 --- a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.cs +++ b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.cs @@ -39,7 +39,7 @@ public void CookieContainer_SetNull_ThrowsArgumentNullException() } } - [Fact] + [SkipOnPlatform(TestPlatforms.Browser, "Credentials is not supported on Browser")] public void Ctor_ExpectedDefaultPropertyValues_CommonPlatform() { using (HttpClientHandler handler = CreateHttpClientHandler()) @@ -62,6 +62,7 @@ public void Ctor_ExpectedDefaultPropertyValues_CommonPlatform() } [Fact] + [SkipOnPlatform(TestPlatforms.Browser, "MaxResponseHeadersLength is not supported on Browser")] public void Ctor_ExpectedDefaultPropertyValues() { using (HttpClientHandler handler = CreateHttpClientHandler()) @@ -79,6 +80,7 @@ public void Ctor_ExpectedDefaultPropertyValues() } [Fact] + [SkipOnPlatform(TestPlatforms.Browser, "Credentials is not supported on Browser")] public void Credentials_SetGet_Roundtrips() { using (HttpClientHandler handler = CreateHttpClientHandler()) @@ -99,6 +101,7 @@ public void Credentials_SetGet_Roundtrips() [Theory] [InlineData(-1)] [InlineData(0)] + [SkipOnPlatform(TestPlatforms.Browser, "MaxAutomaticRedirections not supported on Browser")] public void MaxAutomaticRedirections_InvalidValue_Throws(int redirects) { using (HttpClientHandler handler = CreateHttpClientHandler()) @@ -148,6 +151,7 @@ public void Properties_AddItemToDictionary_ItemPresent() } [Fact] + [SkipOnPlatform(TestPlatforms.Browser, "ServerCertificateCustomValidationCallback not supported on Browser")] public async Task GetAsync_IPv6LinkLocalAddressUri_Success() { if (IsWinHttpHandler && UseVersion >= HttpVersion20.Value) @@ -195,7 +199,10 @@ public async Task GetAsync_IPBasedUri_Success(IPAddress address) } using HttpClientHandler handler = CreateHttpClientHandler(); - handler.ServerCertificateCustomValidationCallback = TestHelper.AllowAllCertificates; + if (PlatformDetection.IsNotBrowser) + { + handler.ServerCertificateCustomValidationCallback = TestHelper.AllowAllCertificates; + } using HttpClient client = CreateHttpClient(handler); @@ -224,6 +231,7 @@ public static IEnumerable GetAsync_IPBasedUri_Success_MemberData() [Theory] [InlineData("[::1234]")] [InlineData("[::1234]:8080")] + [SkipOnPlatform(TestPlatforms.Browser, "Proxy not supported on Browser")] public async Task GetAsync_IPv6AddressInHostHeader_CorrectlyFormatted(string host) { string ipv6Address = "http://" + host; @@ -254,7 +262,9 @@ await LoopbackServer.CreateClientAndServerAsync(async proxyUri => public static IEnumerable SecureAndNonSecure_IPBasedUri_MemberData() => from address in new[] { IPAddress.Loopback, IPAddress.IPv6Loopback } - from useSsl in BoolValues + from useSsl in BoolValues + // we could not create SslStream in browser, [ActiveIssue("https://github.com/dotnet/runtime/issues/37669", TestPlatforms.Browser)] + where PlatformDetection.IsNotBrowser || !useSsl select new object[] { address, useSsl }; [Theory] @@ -267,7 +277,7 @@ public async Task GetAsync_SecureAndNonSecureIPBasedUri_CorrectlyFormatted(IPAdd return; } - var options = new LoopbackServer.Options { Address = address, UseSsl= useSsl }; + var options = new LoopbackServer.Options { Address = address, UseSsl = useSsl }; bool connectionAccepted = false; string host = ""; @@ -277,8 +287,9 @@ await LoopbackServer.CreateClientAndServerAsync(async url => using (HttpClientHandler handler = CreateHttpClientHandler()) using (HttpClient client = CreateHttpClient(handler)) { - if (useSsl) + if (useSsl && PlatformDetection.IsNotBrowser) { + // we could not create SslStream in browser, [ActiveIssue("https://github.com/dotnet/runtime/issues/37669", TestPlatforms.Browser)] handler.ServerCertificateCustomValidationCallback = TestHelper.AllowAllCertificates; } try { await client.GetAsync(url); } catch { } @@ -296,6 +307,7 @@ await LoopbackServer.CreateClientAndServerAsync(async url => [Theory] [InlineData("WWW-Authenticate", "CustomAuth")] [InlineData("", "")] // RFC7235 requires servers to send this header with 401 but some servers don't. + [SkipOnPlatform(TestPlatforms.Browser, "Credentials is not supported on Browser")] public async Task GetAsync_ServerNeedsNonStandardAuthAndSetCredential_StatusCodeUnauthorized(string authHeadrName, string authHeaderValue) { if (IsWinHttpHandler && UseVersion >= HttpVersion20.Value) @@ -328,6 +340,7 @@ await LoopbackServerFactory.CreateServerAsync(async (server, url) => [InlineData("nocolon")] [InlineData("no colon")] [InlineData("Content-Length ")] + [ActiveIssue("https://github.com/dotnet/runtime/issues/54160", TestPlatforms.Browser)] public async Task GetAsync_InvalidHeaderNameValue_ThrowsHttpRequestException(string invalidHeader) { if (UseVersion == HttpVersion30) @@ -341,7 +354,7 @@ await LoopbackServer.CreateClientAndServerAsync(async uri => { await Assert.ThrowsAsync(() => client.GetStringAsync(uri)); } - }, server => server.AcceptConnectionSendCustomResponseAndCloseAsync($"HTTP/1.1 200 OK\r\n{invalidHeader}\r\nContent-Length: 11\r\n\r\nhello world")); + }, server => server.AcceptConnectionSendCustomResponseAndCloseAsync($"HTTP/1.1 200 OK\r\n{invalidHeader}\r\n{LoopbackServer.CorsHeaders}Content-Length: 11\r\n\r\nhello world")); } [Theory] @@ -349,6 +362,7 @@ await LoopbackServer.CreateClientAndServerAsync(async uri => [InlineData(true, false)] [InlineData(false, true)] [InlineData(true, true)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/54160", TestPlatforms.Browser)] public async Task GetAsync_IncompleteData_ThrowsHttpRequestException(bool failDuringHeaders, bool getString) { if (IsWinHttpHandler) @@ -372,8 +386,8 @@ await LoopbackServer.CreateClientAndServerAsync(async uri => } }, server => failDuringHeaders ? - server.AcceptConnectionSendCustomResponseAndCloseAsync("HTTP/1.1 200 OK\r\nContent-Length: 5\r\n") : - server.AcceptConnectionSendCustomResponseAndCloseAsync("HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\nhe")); + server.AcceptConnectionSendCustomResponseAndCloseAsync($"HTTP/1.1 200 OK\r\n{LoopbackServer.CorsHeaders}Content-Length: 5\r\n") : + server.AcceptConnectionSendCustomResponseAndCloseAsync($"HTTP/1.1 200 OK\r\n{LoopbackServer.CorsHeaders}Content-Length: 5\r\n\r\nhe")); } [Fact] @@ -396,10 +410,13 @@ await LoopbackServerFactory.CreateClientAndServerAsync(async uri => var request = new HttpRequestMessage(HttpMethod.Post, uri) { Content = new ByteArrayContent(contentArray), Version = UseVersion }; request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("text/plain")); - request.Headers.AcceptCharset.Add(new StringWithQualityHeaderValue("utf-8")); - request.Headers.AcceptEncoding.Add(new StringWithQualityHeaderValue("gzip")); - request.Headers.AcceptEncoding.Add(new StringWithQualityHeaderValue("deflate")); - request.Headers.AcceptLanguage.Add(new StringWithQualityHeaderValue("en-US")); + if (PlatformDetection.IsNotBrowser) + { + request.Headers.AcceptCharset.Add(new StringWithQualityHeaderValue("utf-8")); + request.Headers.AcceptEncoding.Add(new StringWithQualityHeaderValue("gzip")); + request.Headers.AcceptEncoding.Add(new StringWithQualityHeaderValue("deflate")); + request.Headers.AcceptLanguage.Add(new StringWithQualityHeaderValue("en-US")); + } request.Headers.Add("Accept-Datetime", "Thu, 31 May 2007 20:35:00 GMT"); request.Headers.Add("Access-Control-Request-Method", "GET"); request.Headers.Add("Access-Control-Request-Headers", "GET"); @@ -409,7 +426,10 @@ await LoopbackServerFactory.CreateClientAndServerAsync(async uri => request.Headers.Connection.Add("close"); request.Headers.Add("Cookie", "$Version=1; Skin=new"); request.Content.Headers.ContentLength = contentArray.Length; - request.Content.Headers.ContentMD5 = MD5.Create().ComputeHash(contentArray); + if (PlatformDetection.IsNotBrowser) + { + request.Content.Headers.ContentMD5 = MD5.Create().ComputeHash(contentArray); + } request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/x-www-form-urlencoded"); request.Headers.Date = DateTimeOffset.Parse("Tue, 15 Nov 1994 08:12:31 GMT"); request.Headers.Expect.Add(new NameValueWithParametersHeaderValue("100-continue")); @@ -431,11 +451,14 @@ await LoopbackServerFactory.CreateClientAndServerAsync(async uri => request.Headers.TE.Add(new TransferCodingWithQualityHeaderValue("deflate")); request.Headers.Trailer.Add("MyTrailer"); request.Headers.TransferEncoding.Add(new TransferCodingHeaderValue("chunked")); - request.Headers.UserAgent.Add(new ProductInfoHeaderValue(new ProductHeaderValue("Mozilla", "5.0"))); - request.Headers.Upgrade.Add(new ProductHeaderValue("HTTPS", "1.3")); - request.Headers.Upgrade.Add(new ProductHeaderValue("IRC", "6.9")); - request.Headers.Upgrade.Add(new ProductHeaderValue("RTA", "x11")); - request.Headers.Upgrade.Add(new ProductHeaderValue("websocket")); + if (PlatformDetection.IsNotBrowser) + { + request.Headers.UserAgent.Add(new ProductInfoHeaderValue(new ProductHeaderValue("Mozilla", "5.0"))); + request.Headers.Upgrade.Add(new ProductHeaderValue("HTTPS", "1.3")); + request.Headers.Upgrade.Add(new ProductHeaderValue("IRC", "6.9")); + request.Headers.Upgrade.Add(new ProductHeaderValue("RTA", "x11")); + request.Headers.Upgrade.Add(new ProductHeaderValue("websocket")); + } request.Headers.Via.Add(new ViaHeaderValue("1.0", "fred")); request.Headers.Via.Add(new ViaHeaderValue("1.1", "example.com", null, "(Apache/1.1)")); request.Headers.Warning.Add(new WarningHeaderValue(199, "-", "\"Miscellaneous warning\"")); @@ -471,18 +494,31 @@ await LoopbackServerFactory.CreateClientAndServerAsync(async uri => Assert.Equal(content, Encoding.ASCII.GetString(requestData.Body)); - Assert.Equal("utf-8", requestData.GetSingleHeaderValue("Accept-Charset")); - Assert.Equal("gzip, deflate", requestData.GetSingleHeaderValue("Accept-Encoding")); - Assert.Equal("en-US", requestData.GetSingleHeaderValue("Accept-Language")); - Assert.Equal("Thu, 31 May 2007 20:35:00 GMT", requestData.GetSingleHeaderValue("Accept-Datetime")); - Assert.Equal("GET", requestData.GetSingleHeaderValue("Access-Control-Request-Method")); - Assert.Equal("GET", requestData.GetSingleHeaderValue("Access-Control-Request-Headers")); + if (PlatformDetection.IsNotBrowser) + { + Assert.Equal("utf-8", requestData.GetSingleHeaderValue("Accept-Charset")); + Assert.Equal("gzip, deflate", requestData.GetSingleHeaderValue("Accept-Encoding")); + Assert.Equal("en-US", requestData.GetSingleHeaderValue("Accept-Language")); + Assert.Equal("Thu, 31 May 2007 20:35:00 GMT", requestData.GetSingleHeaderValue("Accept-Datetime")); + Assert.Equal("GET", requestData.GetSingleHeaderValue("Access-Control-Request-Method")); + Assert.Equal("GET", requestData.GetSingleHeaderValue("Access-Control-Request-Headers")); + } Assert.Equal("12", requestData.GetSingleHeaderValue("Age")); Assert.Equal("Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==", requestData.GetSingleHeaderValue("Authorization")); Assert.Equal("no-cache", requestData.GetSingleHeaderValue("Cache-Control")); - Assert.Equal("$Version=1; Skin=new", requestData.GetSingleHeaderValue("Cookie")); - Assert.Equal("Tue, 15 Nov 1994 08:12:31 GMT", requestData.GetSingleHeaderValue("Date")); - Assert.Equal("100-continue", requestData.GetSingleHeaderValue("Expect")); + if (PlatformDetection.IsNotBrowser) + { + Assert.Equal("$Version=1; Skin=new", requestData.GetSingleHeaderValue("Cookie")); + Assert.Equal("Tue, 15 Nov 1994 08:12:31 GMT", requestData.GetSingleHeaderValue("Date")); + Assert.Equal("100-continue", requestData.GetSingleHeaderValue("Expect")); + Assert.Equal("http://www.example-social-network.com", requestData.GetSingleHeaderValue("Origin")); + Assert.Equal("Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==", requestData.GetSingleHeaderValue("Proxy-Authorization")); + Assert.Equal("Mozilla/5.0", requestData.GetSingleHeaderValue("User-Agent")); + Assert.Equal("http://en.wikipedia.org/wiki/Main_Page", requestData.GetSingleHeaderValue("Referer")); + Assert.Equal("MyTrailer", requestData.GetSingleHeaderValue("Trailer")); + Assert.Equal("1.0 fred, 1.1 example.com (Apache/1.1)", requestData.GetSingleHeaderValue("Via")); + Assert.Equal("1 (Do Not Track Enabled)", requestData.GetSingleHeaderValue("DNT")); + } Assert.Equal("for=192.0.2.60;proto=http;by=203.0.113.43", requestData.GetSingleHeaderValue("Forwarded")); Assert.Equal("User Name ", requestData.GetSingleHeaderValue("From")); Assert.Equal("\"37060cd8c284d8af7ad3082f209582d\"", requestData.GetSingleHeaderValue("If-Match")); @@ -491,17 +527,10 @@ await LoopbackServerFactory.CreateClientAndServerAsync(async uri => Assert.Equal("Wed, 21 Oct 2015 07:28:00 GMT", requestData.GetSingleHeaderValue("If-Range")); Assert.Equal("Sat, 29 Oct 1994 19:43:31 GMT", requestData.GetSingleHeaderValue("If-Unmodified-Since")); Assert.Equal("10", requestData.GetSingleHeaderValue("Max-Forwards")); - Assert.Equal("http://www.example-social-network.com", requestData.GetSingleHeaderValue("Origin")); Assert.Equal("no-cache", requestData.GetSingleHeaderValue("Pragma")); - Assert.Equal("Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==", requestData.GetSingleHeaderValue("Proxy-Authorization")); Assert.Equal("bytes=500-999", requestData.GetSingleHeaderValue("Range")); - Assert.Equal("http://en.wikipedia.org/wiki/Main_Page", requestData.GetSingleHeaderValue("Referer")); - Assert.Equal("MyTrailer", requestData.GetSingleHeaderValue("Trailer")); - Assert.Equal("Mozilla/5.0", requestData.GetSingleHeaderValue("User-Agent")); - Assert.Equal("1.0 fred, 1.1 example.com (Apache/1.1)", requestData.GetSingleHeaderValue("Via")); Assert.Equal("199 - \"Miscellaneous warning\"", requestData.GetSingleHeaderValue("Warning")); Assert.Equal("XMLHttpRequest", requestData.GetSingleHeaderValue("X-Requested-With")); - Assert.Equal("1 (Do Not Track Enabled)", requestData.GetSingleHeaderValue("DNT")); Assert.Equal("client1, proxy1, proxy2", requestData.GetSingleHeaderValue("X-Forwarded-For")); Assert.Equal("en.wikipedia.org:8080", requestData.GetSingleHeaderValue("X-Forwarded-Host")); Assert.Equal("https", requestData.GetSingleHeaderValue("X-Forwarded-Proto")); @@ -527,7 +556,7 @@ await LoopbackServerFactory.CreateClientAndServerAsync(async uri => Assert.Equal(0, requestData.GetHeaderValueCount("Connection")); Assert.Equal(0, requestData.GetHeaderValueCount("Transfer-Encoding")); } - else + else if (PlatformDetection.IsNotBrowser) { // Verify HTTP/1.x headers Assert.Equal("close", requestData.GetSingleHeaderValue("Connection"), StringComparer.OrdinalIgnoreCase); // NetFxHandler uses "Close" vs "close" @@ -565,7 +594,10 @@ await LoopbackServer.CreateClientAndServerAsync(async uri => { Assert.Equal("1.1", resp.Version.ToString()); Assert.Equal(HttpStatusCode.OK, resp.StatusCode); - Assert.Contains("*", resp.Headers.GetValues("Access-Control-Allow-Origin")); + if (PlatformDetection.IsNotBrowser) + { + Assert.Contains("*", resp.Headers.GetValues("Access-Control-Allow-Origin")); + } Assert.Contains("text/example;charset=utf-8", resp.Headers.GetValues("Accept-Patch")); Assert.Contains("bytes", resp.Headers.AcceptRanges); Assert.Equal(TimeSpan.FromSeconds(12), resp.Headers.Age.GetValueOrDefault()); @@ -581,7 +613,10 @@ await LoopbackServer.CreateClientAndServerAsync(async uri => Assert.Contains("gzip", resp.Content.Headers.ContentEncoding); Assert.Contains("da", resp.Content.Headers.ContentLanguage); Assert.Equal(new Uri("/index.htm", UriKind.Relative), resp.Content.Headers.ContentLocation); - Assert.Equal(Convert.FromBase64String("Q2hlY2sgSW50ZWdyaXR5IQ=="), resp.Content.Headers.ContentMD5); + if (PlatformDetection.IsNotBrowser) + { + Assert.Equal(Convert.FromBase64String("Q2hlY2sgSW50ZWdyaXR5IQ=="), resp.Content.Headers.ContentMD5); + } Assert.Equal("bytes", resp.Content.Headers.ContentRange.Unit); Assert.Equal(21010, resp.Content.Headers.ContentRange.From.GetValueOrDefault()); Assert.Equal(47021, resp.Content.Headers.ContentRange.To.GetValueOrDefault()); @@ -600,7 +635,11 @@ await LoopbackServer.CreateClientAndServerAsync(async uri => Assert.Contains("max-age=2592000; pin-sha256=\"E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=\"", resp.Headers.GetValues("Public-Key-Pins")); Assert.Equal(TimeSpan.FromSeconds(120), resp.Headers.RetryAfter.Delta.GetValueOrDefault()); Assert.Contains(new ProductInfoHeaderValue("Apache", "2.4.1"), resp.Headers.Server); - Assert.Contains("UserID=JohnDoe; Max-Age=3600; Version=1", resp.Headers.GetValues("Set-Cookie")); + + if (PlatformDetection.IsNotBrowser) + { + Assert.Contains("UserID=JohnDoe; Max-Age=3600; Version=1", resp.Headers.GetValues("Set-Cookie")); + } Assert.Contains("max-age=16070400; includeSubDomains", resp.Headers.GetValues("Strict-Transport-Security")); Assert.Contains("Max-Forwards", resp.Headers.Trailer); Assert.Contains("?", resp.Headers.GetValues("Tk")); @@ -627,6 +666,7 @@ await LoopbackServer.CreateClientAndServerAsync(async uri => }, server => server.AcceptConnectionSendCustomResponseAndCloseAsync( $"HTTP/1.1 200 OK{newline}" + $"Access-Control-Allow-Origin:{fold} *{newline}" + + $"Access-Control-Expose-Headers:{fold} *{newline}" + $"Accept-Patch:{fold} text/example;charset=utf-8{newline}" + $"Accept-Ranges:{fold} bytes{newline}" + $"Age: {fold}12{newline}" + @@ -682,6 +722,7 @@ await LoopbackServer.CreateClientAndServerAsync(async uri => } [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/54160", TestPlatforms.Browser)] public async Task GetAsync_NonTraditionalChunkSizes_Accepted() { if (LoopbackServerFactory.Version >= HttpVersion20.Value) @@ -700,6 +741,7 @@ await TestHelper.WhenAllCompletedOrAnyFailed( server.AcceptConnectionSendCustomResponseAndCloseAsync( "HTTP/1.1 200 OK\r\n" + "Connection: close\r\n" + + LoopbackServer.CorsHeaders + "Transfer-Encoding: chunked\r\n" + "\r\n" + "4 \r\n" + // whitespace after size @@ -733,6 +775,7 @@ await TestHelper.WhenAllCompletedOrAnyFailed( [InlineData("xyz")] // non-hex [InlineData("7gibberish")] // valid size then gibberish [InlineData("7\v\f")] // unacceptable whitespace + [ActiveIssue("https://github.com/dotnet/runtime/issues/54160", TestPlatforms.Browser)] public async Task GetAsync_InvalidChunkSize_ThrowsHttpRequestException(string chunkSize) { if (UseVersion != HttpVersion.Version11) @@ -745,6 +788,7 @@ await LoopbackServer.CreateServerAsync(async (server, url) => using (HttpClient client = CreateHttpClient()) { string partialResponse = "HTTP/1.1 200 OK\r\n" + + LoopbackServer.CorsHeaders + "Transfer-Encoding: chunked\r\n" + "\r\n" + $"{chunkSize}\r\n"; @@ -764,6 +808,7 @@ await LoopbackServer.CreateServerAsync(async (server, url) => } [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/54160", TestPlatforms.Browser)] public async Task GetAsync_InvalidChunkTerminator_ThrowsHttpRequestException() { if (UseVersion != HttpVersion.Version11) @@ -780,6 +825,7 @@ await LoopbackServer.CreateClientAndServerAsync(async url => }, server => server.AcceptConnectionSendCustomResponseAndCloseAsync( "HTTP/1.1 200 OK\r\n" + "Connection: close\r\n" + + LoopbackServer.CorsHeaders + "Transfer-Encoding: chunked\r\n" + "\r\n" + "5\r\n" + @@ -791,6 +837,7 @@ await LoopbackServer.CreateClientAndServerAsync(async url => } [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/54160", TestPlatforms.Browser)] public async Task GetAsync_InfiniteChunkSize_ThrowsHttpRequestException() { if (UseVersion != HttpVersion.Version11) @@ -808,7 +855,7 @@ await LoopbackServer.CreateServerAsync(async (server, url) => var tcs = new TaskCompletionSource(); Task serverTask = server.AcceptConnectionAsync(async connection => { - await connection.ReadRequestHeaderAndSendCustomResponseAsync("HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n"); + await connection.ReadRequestHeaderAndSendCustomResponseAsync("HTTP/1.1 200 OK\r\n" + LoopbackServer.CorsHeaders + "Transfer-Encoding: chunked\r\n\r\n"); try { while (!cts.IsCancellationRequested) // infinite to make sure implementation doesn't OOM @@ -828,6 +875,7 @@ await LoopbackServer.CreateServerAsync(async (server, url) => } [Fact] + [SkipOnPlatform(TestPlatforms.Browser, "CORS is required on Browser")] public async Task SendAsync_TransferEncodingSetButNoRequestContent_Throws() { var req = new HttpRequestMessage(HttpMethod.Post, "http://bing.com") { Version = UseVersion }; @@ -841,6 +889,7 @@ public async Task SendAsync_TransferEncodingSetButNoRequestContent_Throws() [OuterLoop("Slow response")] [Fact] + [SkipOnPlatform(TestPlatforms.Browser, "This is blocking forever on Browser, there is infinite default timeout")] public async Task SendAsync_ReadFromSlowStreamingServer_PartialDataReturned() { if (UseVersion != HttpVersion.Version11) @@ -856,9 +905,14 @@ await LoopbackServer.CreateServerAsync(async (server, url) => await server.AcceptConnectionAsync(async connection => { - await connection.ReadRequestHeaderAndSendCustomResponseAsync( + HttpRequestData requestData = await connection.ReadRequestDataAsync(); +#if TARGET_BROWSER + await connection.HandleCORSPreFlight(requestData); +#endif + await connection.WriteStringAsync( "HTTP/1.1 200 OK\r\n" + $"Date: {DateTimeOffset.UtcNow:R}\r\n" + + LoopbackServer.CorsHeaders + "Content-Length: 16000\r\n" + "\r\n" + "less than 16000 bytes"); @@ -882,6 +936,7 @@ await connection.ReadRequestHeaderAndSendCustomResponseAsync( [InlineData(true)] [InlineData(false)] [InlineData(null)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/54159", TestPlatforms.Browser)] public async Task ReadAsStreamAsync_HandlerProducesWellBehavedResponseStream(bool? chunked) { if (IsWinHttpHandler && UseVersion >= HttpVersion20.Value) @@ -1047,6 +1102,7 @@ await server.AcceptConnectionAsync(async connection => } [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/54159", TestPlatforms.Browser)] public async Task ReadAsStreamAsync_EmptyResponseBody_HandlerProducesWellBehavedResponseStream() { if (IsWinHttpHandler && UseVersion >= HttpVersion20.Value) @@ -1211,6 +1267,7 @@ await LoopbackServerFactory.CreateServerAsync(async (server3, url3) => [Theory] [InlineData(99)] [InlineData(1000)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/54160", TestPlatforms.Browser)] public async Task GetAsync_StatusCodeOutOfRange_ExpectedException(int statusCode) { if (UseVersion == HttpVersion30) @@ -1227,6 +1284,7 @@ await LoopbackServer.CreateServerAsync(async (server, url) => await server.AcceptConnectionSendCustomResponseAndCloseAsync( $"HTTP/1.1 {statusCode}\r\n" + $"Date: {DateTimeOffset.UtcNow:R}\r\n" + + LoopbackServer.CorsHeaders + "Connection: close\r\n" + "\r\n"); @@ -1255,6 +1313,7 @@ public async Task GetAsync_UnicodeHostName_SuccessStatusCodeInResponse() #region Post Methods Tests [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/53876", TestPlatforms.Browser)] public async Task GetAsync_ExpectContinueTrue_NoContent_StillSendsHeader() { if (IsWinHttpHandler && UseVersion >= HttpVersion20.Value) @@ -1306,6 +1365,7 @@ public static IEnumerable Interim1xxStatusCode() [Theory] [MemberData(nameof(Interim1xxStatusCode))] + [SkipOnPlatform(TestPlatforms.Browser, "CookieContainer is not supported on Browser")] public async Task SendAsync_1xxResponsesWithHeaders_InterimResponsesHeadersIgnored(HttpStatusCode responseStatusCode) { if (IsWinHttpHandler && UseVersion >= HttpVersion20.Value) @@ -1480,6 +1540,7 @@ await server.AcceptConnectionAsync(async connection => } [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/54160", TestPlatforms.Browser)] public async Task SendAsync_Expect100Continue_RequestBodyFails_ThrowsContentException() { if (IsWinHttpHandler) @@ -1576,6 +1637,7 @@ await server.AcceptConnectionAsync(async connection => } [Fact] + [SkipOnPlatform(TestPlatforms.Browser, "Switching protocol is not supported on Browser")] public async Task SendAsync_101SwitchingProtocolsResponse_Success() { // WinHttpHandler and CurlHandler will hang, waiting for additional response. @@ -1616,6 +1678,7 @@ await connection.ReadRequestHeaderAndSendCustomResponseAsync( [Theory] [InlineData(false)] [InlineData(true)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/54160", TestPlatforms.Browser)] public async Task PostAsync_ThrowFromContentCopy_RequestFails(bool syncFailure) { if (UseVersion == HttpVersion30) @@ -1629,7 +1692,7 @@ await LoopbackServer.CreateServerAsync(async (server, uri) => Task responseTask = server.AcceptConnectionAsync(async connection => { var buffer = new byte[1000]; - while (await connection.Socket.ReceiveAsync(new ArraySegment(buffer, 0, buffer.Length), SocketFlags.None) != 0); + while (await connection.ReadAsync(new Memory(buffer), 0, buffer.Length) != 0) ; }); using (HttpClient client = CreateHttpClient()) @@ -1651,6 +1714,7 @@ await LoopbackServer.CreateServerAsync(async (server, uri) => [Theory] [InlineData(HttpStatusCode.MethodNotAllowed, "Custom description")] [InlineData(HttpStatusCode.MethodNotAllowed, "")] + [ActiveIssue("https://github.com/dotnet/runtime/issues/54163", TestPlatforms.Browser)] public async Task GetAsync_CallMethod_ExpectedStatusLine(HttpStatusCode statusCode, string reasonPhrase) { if (LoopbackServerFactory.Version >= HttpVersion20.Value) @@ -1668,13 +1732,14 @@ await LoopbackServer.CreateClientAndServerAsync(async uri => Assert.Equal(reasonPhrase, response.ReasonPhrase); } }, server => server.AcceptConnectionSendCustomResponseAndCloseAsync( - $"HTTP/1.1 {(int)statusCode} {reasonPhrase}\r\nContent-Length: 0\r\n\r\n")); + $"HTTP/1.1 {(int)statusCode} {reasonPhrase}\r\n{LoopbackServer.CorsHeaders}Content-Length: 0\r\n\r\n")); } #endregion #region Version tests + [SkipOnPlatform(TestPlatforms.Browser, "Version is not supported on Browser")] [Fact] public async Task SendAsync_RequestVersion10_ServerReceivesVersion10Request() { @@ -1688,6 +1753,7 @@ public async Task SendAsync_RequestVersion10_ServerReceivesVersion10Request() Assert.Equal(new Version(1, 0), receivedRequestVersion); } + [SkipOnPlatform(TestPlatforms.Browser, "Version is not supported on Browser")] [Fact] public async Task SendAsync_RequestVersion11_ServerReceivesVersion11Request() { @@ -1695,6 +1761,7 @@ public async Task SendAsync_RequestVersion11_ServerReceivesVersion11Request() Assert.Equal(new Version(1, 1), receivedRequestVersion); } + [SkipOnPlatform(TestPlatforms.Browser, "Version is not supported on Browser")] [Fact] public async Task SendAsync_RequestVersionNotSpecified_ServerReceivesVersion11Request() { diff --git a/src/libraries/Common/tests/System/Net/Http/LoopbackServer.cs b/src/libraries/Common/tests/System/Net/Http/LoopbackServer.cs index b44ae2d7f6803..5685e79cdb602 100644 --- a/src/libraries/Common/tests/System/Net/Http/LoopbackServer.cs +++ b/src/libraries/Common/tests/System/Net/Http/LoopbackServer.cs @@ -11,6 +11,7 @@ using System.Text; using System.Threading; using System.Threading.Tasks; +using System.Net.WebSockets; using Xunit; namespace System.Net.Test.Common @@ -20,55 +21,83 @@ public sealed partial class LoopbackServer : GenericLoopbackServer, IDisposable private static readonly byte[] s_newLineBytes = new byte[] { (byte)'\r', (byte)'\n' }; private static readonly byte[] s_colonSpaceBytes = new byte[] { (byte)':', (byte)' ' }; + private SocketWrapper _socketWrapper; +#if TARGET_BROWSER + private ClientWebSocket _listenSocket; +#else private Socket _listenSocket; +#endif private Options _options; private Uri _uri; public LoopbackServer(Options options = null) { _options = options ??= new Options(); + } + +#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously + public async Task ListenAsync() +#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously + { try { - _listenSocket = new Socket(options.Address.AddressFamily, SocketType.Stream, ProtocolType.Tcp); - _listenSocket.Bind(new IPEndPoint(options.Address, 0)); - _listenSocket.Listen(options.ListenBacklog); + IPEndPoint localEndPoint; +#if TARGET_BROWSER + _listenSocket = new ClientWebSocket(); - var localEndPoint = (IPEndPoint)_listenSocket.LocalEndPoint; - string host = options.Address.AddressFamily == AddressFamily.InterNetworkV6 ? + await _listenSocket.ConnectAsync(Configuration.Http.RemoteLoopServer, CancellationToken.None); + + byte[] buffer = new byte[128 * 1024]; + var message = Encoding.ASCII.GetBytes($"{_options.ListenBacklog},{_options.Address}"); + await _listenSocket.SendAsync(message, WebSocketMessageType.Binary, true, CancellationToken.None); + var first = await _listenSocket.ReceiveAsync(buffer, CancellationToken.None); + localEndPoint = IPEndPoint.Parse(Encoding.ASCII.GetString(buffer, 0, first.Count)); +#else + _listenSocket = new Socket(_options.Address.AddressFamily, SocketType.Stream, ProtocolType.Tcp); + _listenSocket.Bind(new IPEndPoint(_options.Address, 0)); + _listenSocket.Listen(_options.ListenBacklog); + localEndPoint = (IPEndPoint)_listenSocket.LocalEndPoint; +#endif + + string host = _options.Address.AddressFamily == AddressFamily.InterNetworkV6 ? $"[{localEndPoint.Address}]" : localEndPoint.Address.ToString(); - string scheme = options.UseSsl ? "https" : "http"; - if (options.WebSocketEndpoint) + string scheme = _options.UseSsl ? "https" : "http"; + if (_options.WebSocketEndpoint) { - scheme = options.UseSsl ? "wss" : "ws"; + scheme = _options.UseSsl ? "wss" : "ws"; } _uri = new Uri($"{scheme}://{host}:{localEndPoint.Port}/"); + _socketWrapper = new SocketWrapper(_listenSocket); } catch { _listenSocket?.Dispose(); + _socketWrapper?.Dispose(); throw; } } public override void Dispose() { - if (_listenSocket != null) + _listenSocket = null; + if (_socketWrapper != null) { - _listenSocket.Dispose(); - _listenSocket = null; + _socketWrapper.Dispose(); + _socketWrapper = null; } } - public Socket ListenSocket => _listenSocket; + public SocketWrapper ListenSocket => _socketWrapper; public override Uri Address => _uri; public static async Task CreateServerAsync(Func funcAsync, Options options = null) { using (var server = new LoopbackServer(options)) { + await server.ListenAsync(); await funcAsync(server).ConfigureAwait(false); } } @@ -96,23 +125,31 @@ public override async Task EstablishGenericConnection public async Task EstablishConnectionAsync() { - Socket s = await _listenSocket.AcceptAsync().ConfigureAwait(false); + SocketWrapper closableWrapper = null; try { + Stream stream = null; +#if TARGET_BROWSER + closableWrapper = new SocketWrapper(_listenSocket); + stream = new WebSocketStream(_listenSocket, ownsSocket: true); +#else + var socket = await _listenSocket.AcceptAsync().ConfigureAwait(false); + closableWrapper = new SocketWrapper(socket); + try { - s.NoDelay = true; + socket.NoDelay = true; } // OSX can throw if socket is in weird state during close or cancellation catch (SocketException ex) when (ex.SocketErrorCode == SocketError.InvalidArgument && PlatformDetection.IsOSXLike) { } - Stream stream = new NetworkStream(s, ownsSocket: false); - - return await Connection.CreateAsync(s, stream, _options); + stream = new NetworkStream(socket, ownsSocket: false); +#endif + return await Connection.CreateAsync(closableWrapper, stream, _options).ConfigureAwait(false); } catch (Exception) { - s.Close(); + closableWrapper?.Close(); throw; } } @@ -332,11 +369,19 @@ public static string GetHttpResponse(HttpStatusCode statusCode = HttpStatusCode. public static string GetHttpResponseHeaders(HttpStatusCode statusCode = HttpStatusCode.OK, string additionalHeaders = null, string content = null, bool connectionClose = false) => GetHttpResponseHeaders(statusCode, additionalHeaders, content == null ? 0 : content.Length, connectionClose); + public static string CorsHeaders = PlatformDetection.IsBrowser + ? "Access-Control-Allow-Methods: GET, POST, OPTIONS, PUT, DELETE\r\n" + + "Access-Control-Expose-Headers: *\r\n" + + "Access-Control-Allow-Headers: *\r\n" + + "Access-Control-Allow-Origin: *\r\n" + : ""; + public static string GetHttpResponseHeaders(HttpStatusCode statusCode = HttpStatusCode.OK, string additionalHeaders = null, int contentLength = 0, bool connectionClose = false) => $"HTTP/1.1 {(int)statusCode} {GetStatusDescription(statusCode)}\r\n" + (connectionClose ? "Connection: close\r\n" : "") + $"Date: {DateTimeOffset.UtcNow:R}\r\n" + $"Content-Length: {contentLength}\r\n" + + CorsHeaders + additionalHeaders + "\r\n"; @@ -345,6 +390,7 @@ public static string GetSingleChunkHttpResponse(HttpStatusCode statusCode = Http (connectionClose ? "Connection: close\r\n" : "") + $"Date: {DateTimeOffset.UtcNow:R}\r\n" + "Transfer-Encoding: chunked\r\n" + + CorsHeaders + additionalHeaders + "\r\n" + (string.IsNullOrEmpty(content) ? "" : @@ -358,6 +404,7 @@ public static string GetBytePerChunkHttpResponse(HttpStatusCode statusCode = Htt (connectionClose ? "Connection: close\r\n" : "") + $"Date: {DateTimeOffset.UtcNow:R}\r\n" + "Transfer-Encoding: chunked\r\n" + + CorsHeaders + additionalHeaders + "\r\n" + (string.IsNullOrEmpty(content) ? "" : string.Concat(content.Select(c => $"1\r\n{c}\r\n"))) + @@ -368,6 +415,7 @@ public static string GetConnectionCloseResponse(HttpStatusCode statusCode = Http $"HTTP/1.1 {(int)statusCode} {GetStatusDescription(statusCode)}\r\n" + "Connection: close\r\n" + $"Date: {DateTimeOffset.UtcNow:R}\r\n" + + CorsHeaders + additionalHeaders + "\r\n" + content; @@ -395,7 +443,7 @@ public Options() public sealed class Connection : GenericLoopbackConnection { private const int BufferSize = 4000; - private Socket _socket; + private SocketWrapper _socket; private Stream _stream; private byte[] _readBuffer; private int _readStart; @@ -403,7 +451,7 @@ public sealed class Connection : GenericLoopbackConnection private int _contentLength = 0; private bool _bodyRead = false; - public Connection(Socket socket, Stream stream) + public Connection(SocketWrapper socket, Stream stream) { _socket = socket; _stream = stream; @@ -413,10 +461,10 @@ public Connection(Socket socket, Stream stream) _readEnd = 0; } - public Socket Socket => _socket; + public SocketWrapper Socket => _socket; public Stream Stream => _stream; - public static async Task CreateAsync(Socket socket, Stream stream, Options httpOptions) + public static async Task CreateAsync(SocketWrapper socket, Stream stream, Options httpOptions) { if (httpOptions.UseSsl) { @@ -706,6 +754,11 @@ public async Task> ReadRequestHeaderAndSendCustomResponseAsync(byte public async Task> ReadRequestHeaderAndSendResponseAsync(HttpStatusCode statusCode = HttpStatusCode.OK, string additionalHeaders = null, string content = null) { List lines = await ReadRequestHeaderAsync().ConfigureAwait(false); + +#if TARGET_BROWSER + lines = await HandleCORSPreFlight(lines); +#endif + await SendResponseAsync(statusCode, additionalHeaders, content).ConfigureAwait(false); return lines; } @@ -850,6 +903,12 @@ public override async Task SendResponseAsync(HttpStatusCode? statusCode = HttpSt } } + if (PlatformDetection.IsBrowser) + { + byte[] corsBytes = Encoding.ASCII.GetBytes(CorsHeaders); + headerBytes.Write(corsBytes, 0, corsBytes.Length); + } + bool endHeaders = content != null || isFinal; if (statusCode != null) { @@ -890,6 +949,7 @@ public override async Task SendResponseHeadersAsync(HttpStatusCode statusCode = headerString = headerString + $"{headerData.Name}: {headerData.Value}\r\n"; } } + headerString += CorsHeaders; headerString = GetHttpResponseHeaders(statusCode, headerString, 0, connectionClose: true); @@ -901,10 +961,52 @@ public override async Task SendResponseBodyAsync(byte[] body, bool isFinal = tru await SendResponseAsync(body).ConfigureAwait(false); } + public async Task HandleCORSPreFlight(HttpRequestData requestData) + { + if (PlatformDetection.IsBrowser && requestData.Method == "OPTIONS" && requestData.Headers.Any(h => h.Name.StartsWith("Access-Control-Request-Method"))) + { + // handle CORS pre-flight + await SendResponseAsync(HttpStatusCode.OK).ConfigureAwait(false); + + // reset state + _bodyRead = false; + _contentLength = 0; + _readStart = 0; + _readEnd = 0; + + // wait for real request + return await ReadRequestDataAsync().ConfigureAwait(false); + } + return requestData; + } + + public async Task> HandleCORSPreFlight(List lines) + { + if (PlatformDetection.IsBrowser && lines[0].Contains("OPTIONS") && lines.Any(h => h.StartsWith("Access-Control-Request-Method"))) + { + // handle CORS pre-flight + await SendResponseAsync(HttpStatusCode.OK).ConfigureAwait(false); + + // reset state + _bodyRead = false; + _contentLength = 0; + _readStart = 0; + _readEnd = 0; + + // wait for real request + return await ReadRequestHeaderAsync().ConfigureAwait(false); + } + return lines; + } + public override async Task HandleRequestAsync(HttpStatusCode statusCode = HttpStatusCode.OK, IList headers = null, string content = "") { HttpRequestData requestData = await ReadRequestDataAsync().ConfigureAwait(false); +#if TARGET_BROWSER + requestData = await HandleCORSPreFlight(requestData); +#endif + // For historical reasons, we added Date and "Connection: close" (to improve test reliability) bool hasDate = false; List newHeaders = new List(); @@ -970,7 +1072,9 @@ public sealed class Http11LoopbackServerFactory : LoopbackServerFactory public override GenericLoopbackServer CreateServer(GenericLoopbackOptions options = null) { - return new LoopbackServer(CreateOptions(options)); + var loopbackServer = new LoopbackServer(CreateOptions(options)); + Task.WaitAll(loopbackServer.ListenAsync()); + return loopbackServer; } public override Task CreateServerAsync(Func funcAsync, int millisecondsTimeout = 60_000, GenericLoopbackOptions options = null) @@ -978,7 +1082,7 @@ public override Task CreateServerAsync(Func fu return LoopbackServer.CreateServerAsync((server, uri) => funcAsync(server, uri), options: CreateOptions(options)); } - public override async Task CreateConnectionAsync(Socket socket, Stream stream, GenericLoopbackOptions options = null) + public override async Task CreateConnectionAsync(SocketWrapper socket, Stream stream, GenericLoopbackOptions options = null) { return await LoopbackServer.Connection.CreateAsync(socket, stream, CreateOptions(options)); } diff --git a/src/libraries/Common/tests/System/Net/Http/ResponseStreamTest.cs b/src/libraries/Common/tests/System/Net/Http/ResponseStreamTest.cs index 1a6cc656e9257..f6cc44f67e7c9 100644 --- a/src/libraries/Common/tests/System/Net/Http/ResponseStreamTest.cs +++ b/src/libraries/Common/tests/System/Net/Http/ResponseStreamTest.cs @@ -228,11 +228,11 @@ await client.GetAsync(remoteServer.EchoUri, HttpCompletionOption.ResponseHeaders } } #if NETCOREAPP - [ActiveIssue("https://github.com/dotnet/runtime/issues/42852", TestPlatforms.Browser)] [Theory] [InlineData(TransferType.ContentLength, TransferError.ContentLengthTooLarge)] [InlineData(TransferType.Chunked, TransferError.MissingChunkTerminator)] [InlineData(TransferType.Chunked, TransferError.ChunkSizeTooLarge)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/54160", TestPlatforms.Browser)] public async Task ReadAsStreamAsync_InvalidServerResponse_ThrowsIOException( TransferType transferType, TransferError transferError) @@ -243,7 +243,6 @@ await StartTransferTypeAndErrorServer(transferType, transferError, async uri => }); } - [ActiveIssue("https://github.com/dotnet/runtime/issues/42852", TestPlatforms.Browser)] [Theory] [InlineData(TransferType.None, TransferError.None)] [InlineData(TransferType.ContentLength, TransferError.None)] @@ -258,7 +257,6 @@ await StartTransferTypeAndErrorServer(transferType, transferError, async uri => }); } - [ActiveIssue("https://github.com/dotnet/runtime/issues/42852", TestPlatforms.Browser)] [Theory] [InlineData(TransferType.None, TransferError.None)] [InlineData(TransferType.ContentLength, TransferError.None)] @@ -327,6 +325,7 @@ public static Task StartTransferTypeAndErrorServer( // Write response header await connection.WriteStringAsync("HTTP/1.1 200 OK\r\n").ConfigureAwait(false); await connection.WriteStringAsync($"Date: {DateTimeOffset.UtcNow:R}\r\n").ConfigureAwait(false); + await connection.WriteStringAsync(LoopbackServer.CorsHeaders).ConfigureAwait(false); await connection.WriteStringAsync("Content-Type: text/plain\r\n").ConfigureAwait(false); if (!string.IsNullOrEmpty(transferHeader)) { diff --git a/src/libraries/Common/tests/System/Net/Prerequisites/LocalEchoServer.props b/src/libraries/Common/tests/System/Net/Prerequisites/LocalEchoServer.props index 97bdbf298b842..aeed390ba536b 100644 --- a/src/libraries/Common/tests/System/Net/Prerequisites/LocalEchoServer.props +++ b/src/libraries/Common/tests/System/Net/Prerequisites/LocalEchoServer.props @@ -9,9 +9,14 @@ <_TestEchoMiddleware Condition="'$(ContinuousIntegrationBuild)' == 'true' and '$(OS)' != 'Windows_NT'">$HELIX_CORRELATION_PAYLOAD/xharness/TestEchoMiddleware <_TestEchoMiddleware Condition="'$(ContinuousIntegrationBuild)' != 'true'">$(ArtifactsDir)bin/NetCoreServer/$(NetCoreAppCurrent)-$(Configuration) + <_RemoteLoopMiddleware Condition="'$(ContinuousIntegrationBuild)' == 'true' and '$(OS)' == 'Windows_NT'">%HELIX_CORRELATION_PAYLOAD%/xharness/RemoteLoopMiddleware + <_RemoteLoopMiddleware Condition="'$(ContinuousIntegrationBuild)' == 'true' and '$(OS)' != 'Windows_NT'">$HELIX_CORRELATION_PAYLOAD/xharness/RemoteLoopMiddleware + <_RemoteLoopMiddleware Condition="'$(ContinuousIntegrationBuild)' != 'true'">$(ArtifactsDir)bin/RemoteLoopServer/$(NetCoreAppCurrent)-$(Configuration) + $(WasmXHarnessArgs) --web-server-use-cors --web-server-use-https - $(WasmXHarnessArgs) --set-web-server-http-env=DOTNET_TEST_WEBSOCKETHOST,DOTNET_TEST_HTTPHOST + $(WasmXHarnessArgs) --set-web-server-http-env=DOTNET_TEST_WEBSOCKETHOST,DOTNET_TEST_HTTPHOST,DOTNET_TEST_REMOTE_LOOP_HOST $(WasmXHarnessArgs) --set-web-server-https-env=DOTNET_TEST_SECUREWEBSOCKETHOST,DOTNET_TEST_SECUREHTTPHOST,DOTNET_TEST_HTTP2HOST + $(WasmXHarnessArgs) --web-server-middleware=$(_RemoteLoopMiddleware)/RemoteLoopServer.dll,GenericHandler $(WasmXHarnessArgs) --web-server-middleware=$(_TestEchoMiddleware)/NetCoreServer.dll,GenericHandler diff --git a/src/libraries/Common/tests/System/Net/Prerequisites/NetCoreServer.sln b/src/libraries/Common/tests/System/Net/Prerequisites/NetCoreServer.sln deleted file mode 100644 index 8e5d44de5cd87..0000000000000 --- a/src/libraries/Common/tests/System/Net/Prerequisites/NetCoreServer.sln +++ /dev/null @@ -1,25 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.28307.438 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetCoreServer", "NetCoreServer\NetCoreServer.csproj", "{86E9A13D-9F4A-45DE-B0BB-CBB6A6533867}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {86E9A13D-9F4A-45DE-B0BB-CBB6A6533867}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {86E9A13D-9F4A-45DE-B0BB-CBB6A6533867}.Debug|Any CPU.Build.0 = Debug|Any CPU - {86E9A13D-9F4A-45DE-B0BB-CBB6A6533867}.Release|Any CPU.ActiveCfg = Release|Any CPU - {86E9A13D-9F4A-45DE-B0BB-CBB6A6533867}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {2F9A0637-452E-4FB9-9403-CB52944982DA} - EndGlobalSection -EndGlobal diff --git a/src/libraries/Common/tests/System/Net/Prerequisites/NetTestServers.sln b/src/libraries/Common/tests/System/Net/Prerequisites/NetTestServers.sln new file mode 100644 index 0000000000000..4075b414bebf7 --- /dev/null +++ b/src/libraries/Common/tests/System/Net/Prerequisites/NetTestServers.sln @@ -0,0 +1,30 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.31229.75 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RemoteLoopServer", "RemoteLoopServer\RemoteLoopServer.csproj", "{86E9A13D-9F4A-45DE-B0BB-CBB6A6533868}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NetCoreServer", "NetCoreServer\NetCoreServer.csproj", "{2BB687CC-3F0C-43A9-8F38-140E91892EB0}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {86E9A13D-9F4A-45DE-B0BB-CBB6A6533868}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {86E9A13D-9F4A-45DE-B0BB-CBB6A6533868}.Debug|Any CPU.Build.0 = Debug|Any CPU + {86E9A13D-9F4A-45DE-B0BB-CBB6A6533868}.Release|Any CPU.ActiveCfg = Release|Any CPU + {86E9A13D-9F4A-45DE-B0BB-CBB6A6533868}.Release|Any CPU.Build.0 = Release|Any CPU + {2BB687CC-3F0C-43A9-8F38-140E91892EB0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2BB687CC-3F0C-43A9-8F38-140E91892EB0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2BB687CC-3F0C-43A9-8F38-140E91892EB0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2BB687CC-3F0C-43A9-8F38-140E91892EB0}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {2F9A0637-452E-4FB9-9403-CB52944982DA} + EndGlobalSection +EndGlobal diff --git a/src/libraries/Common/tests/System/Net/Prerequisites/RemoteLoopServer/GenericHandler.cs b/src/libraries/Common/tests/System/Net/Prerequisites/RemoteLoopServer/GenericHandler.cs new file mode 100644 index 0000000000000..3f01530103892 --- /dev/null +++ b/src/libraries/Common/tests/System/Net/Prerequisites/RemoteLoopServer/GenericHandler.cs @@ -0,0 +1,47 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.Features; +using Microsoft.Extensions.Logging; + +namespace RemoteLoopServer +{ + public class GenericHandler + { + RequestDelegate _next; + ILogger _logger; + public GenericHandler(RequestDelegate next, ILogger logger) + { + this._next = next; + this._logger = logger; + } + + public async Task Invoke(HttpContext context) + { + PathString path = context.Request.Path; + if (path.Equals(new PathString("/RemoteLoop"))) + { + await RemoteLoopHandler.InvokeAsync(context, _logger); + return; + } + + await _next(context); + } + } + + public static class GenericHandlerExtensions + { + public static IApplicationBuilder UseGenericHandler(this IApplicationBuilder builder) + { + return builder.UseMiddleware(); + } + + public static void SetStatusDescription(this HttpResponse response, string description) + { + response.HttpContext.Features.Get().ReasonPhrase = description; + } + } +} diff --git a/src/libraries/Common/tests/System/Net/Prerequisites/RemoteLoopServer/Handlers/RemoteLoopHandler.cs b/src/libraries/Common/tests/System/Net/Prerequisites/RemoteLoopServer/Handlers/RemoteLoopHandler.cs new file mode 100644 index 0000000000000..4f83c67b0b30f --- /dev/null +++ b/src/libraries/Common/tests/System/Net/Prerequisites/RemoteLoopServer/Handlers/RemoteLoopHandler.cs @@ -0,0 +1,161 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Net; +using System.Net.Sockets; +using System.Net.WebSockets; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Logging; + +namespace RemoteLoopServer +{ + public partial class RemoteLoopHandler + { + public static async Task InvokeAsync(HttpContext context, ILogger logger) + { + try + { + if (!context.WebSockets.IsWebSocketRequest) + { + context.Response.StatusCode = 400; + context.Response.ContentType = "text/plain"; + await context.Response.WriteAsync("Not a websocket request"); + + return; + } + + using (WebSocket socket = await context.WebSockets.AcceptWebSocketAsync()) + { + await ProcessWebSocketRequest(context, socket, logger); + } + + } + catch (Exception ex) + { + logger.LogError("RemoteLoopHandler failed", ex); + } + } + + private static async Task ProcessWebSocketRequest(HttpContext context, WebSocket control, ILogger logger) + { + byte[] controlBuffer = new byte[128 * 1024]; + byte[] testedBuffer = new byte[128 * 1024]; + Socket listenSocket = null; + Socket tested = null; + CancellationTokenSource cts = new CancellationTokenSource(); + try + { + WebSocketReceiveResult first = await control.ReceiveAsync(controlBuffer, cts.Token).ConfigureAwait(false); + if (first.Count <= 0 || first.MessageType != WebSocketMessageType.Binary || control.State != WebSocketState.Open) + { + throw new Exception("Unexpected close"); + } + + // parse setup request + var message = Encoding.ASCII.GetString(controlBuffer, 0, first.Count); + var split = message.Split(','); + var listenBacklog = int.Parse(split[0]); + var address = IPAddress.Parse(split[1]); + + listenSocket = new Socket(address.AddressFamily, SocketType.Stream, ProtocolType.Tcp); + listenSocket.Bind(new IPEndPoint(address, 0)); + listenSocket.Listen(listenBacklog); + EndPoint endPoint = listenSocket.LocalEndPoint; + + // respond with what we have done + await control.SendAsync(Encoding.ASCII.GetBytes(endPoint.ToString()), WebSocketMessageType.Binary, true, cts.Token).ConfigureAwait(false); + + // wait for the tested client to connect + tested = await listenSocket.AcceptAsync().ConfigureAwait(false); + + // now we are connected, pump messages + bool close = false; + + Task testedNext = tested.ReceiveAsync(new Memory(testedBuffer), SocketFlags.None, cts.Token).AsTask(); + Task controlNext = control.ReceiveAsync(controlBuffer, cts.Token); + while (!close) + { + // wait for either message + await Task.WhenAny(testedNext, controlNext).ConfigureAwait(false); + + if (testedNext.IsCompleted) + { + if (testedNext.IsCanceled || testedNext.IsFaulted) + { + close = true; + } + else + { + if (!tested.Connected) + { + close = true; + } + if (testedNext.Result > 0) + { + var slice = new ArraySegment(testedBuffer, 0, testedNext.Result); + await control.SendAsync(slice, WebSocketMessageType.Binary, true, cts.Token).ConfigureAwait(false); + } + if (!close) + { + testedNext = tested.ReceiveAsync(new Memory(testedBuffer), SocketFlags.None, cts.Token).AsTask(); + } + } + } + if (controlNext.IsCompleted) + { + if (controlNext.IsCanceled || controlNext.IsFaulted) + { + close = true; + } + else + { + if (controlNext.Result.MessageType == WebSocketMessageType.Close) + { + close = true; + } + if (controlNext.Result.Count > 0) + { + var slice = new ArraySegment(controlBuffer, 0, controlNext.Result.Count); + await tested.SendAsync(slice, SocketFlags.None, cts.Token).ConfigureAwait(false); + } + if (!close) + { + controlNext = control.ReceiveAsync(new ArraySegment(controlBuffer), cts.Token); + } + } + } + } + if (tested.Connected) + { + tested.Disconnect(false); + } + if (control.State == WebSocketState.Open || control.State == WebSocketState.Connecting || control.State == WebSocketState.None) + { + try + { + await control.CloseAsync(WebSocketCloseStatus.NormalClosure, "closing remoteLoop", cts.Token).ConfigureAwait(false); + } + catch (WebSocketException ex) + { + logger.LogWarning("ProcessWebSocketRequest closing failed", ex); + } + } + cts.Cancel(); + } + catch (Exception ex) + { + logger.LogError("ProcessWebSocketRequest failed", ex); + } + finally + { + tested?.Dispose(); + control?.Dispose(); + } + } + } +} diff --git a/src/libraries/Common/tests/System/Net/Prerequisites/RemoteLoopServer/Program.cs b/src/libraries/Common/tests/System/Net/Prerequisites/RemoteLoopServer/Program.cs new file mode 100644 index 0000000000000..f18d257efb967 --- /dev/null +++ b/src/libraries/Common/tests/System/Net/Prerequisites/RemoteLoopServer/Program.cs @@ -0,0 +1,23 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Hosting; + +namespace RemoteLoopServer +{ + public class Program + { + public static void Main(string[] args) + { + CreateHostBuilder(args).Build().Run(); + } + + public static IHostBuilder CreateHostBuilder(string[] args) => + Host.CreateDefaultBuilder(args) + .ConfigureWebHostDefaults(webBuilder => + { + webBuilder.UseStartup(); + }); + } +} diff --git a/src/libraries/Common/tests/System/Net/Prerequisites/RemoteLoopServer/RemoteLoopServer.csproj b/src/libraries/Common/tests/System/Net/Prerequisites/RemoteLoopServer/RemoteLoopServer.csproj new file mode 100644 index 0000000000000..ba8a85a059c54 --- /dev/null +++ b/src/libraries/Common/tests/System/Net/Prerequisites/RemoteLoopServer/RemoteLoopServer.csproj @@ -0,0 +1,15 @@ + + + + $(AspNetCoreAppCurrent) + InProcess + Exe + + + + + + + + + diff --git a/src/libraries/Common/tests/System/Net/Prerequisites/RemoteLoopServer/Startup.cs b/src/libraries/Common/tests/System/Net/Prerequisites/RemoteLoopServer/Startup.cs new file mode 100644 index 0000000000000..bbf7b7bb79e65 --- /dev/null +++ b/src/libraries/Common/tests/System/Net/Prerequisites/RemoteLoopServer/Startup.cs @@ -0,0 +1,23 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.DependencyInjection; + +namespace RemoteLoopServer +{ + public class Startup + { + public void ConfigureServices(IServiceCollection services) + { + } + + // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + app.UseWebSockets(); + app.UseGenericHandler(); + } + } +} diff --git a/src/libraries/Common/tests/System/Net/Prerequisites/RemoteLoopServer/appsettings.Development.json b/src/libraries/Common/tests/System/Net/Prerequisites/RemoteLoopServer/appsettings.Development.json new file mode 100644 index 0000000000000..e203e9407e74a --- /dev/null +++ b/src/libraries/Common/tests/System/Net/Prerequisites/RemoteLoopServer/appsettings.Development.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Debug", + "System": "Information", + "Microsoft": "Information" + } + } +} diff --git a/src/libraries/Common/tests/System/Net/Prerequisites/RemoteLoopServer/appsettings.json b/src/libraries/Common/tests/System/Net/Prerequisites/RemoteLoopServer/appsettings.json new file mode 100644 index 0000000000000..def9159a7d940 --- /dev/null +++ b/src/libraries/Common/tests/System/Net/Prerequisites/RemoteLoopServer/appsettings.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Warning" + } + }, + "AllowedHosts": "*" +} diff --git a/src/libraries/Common/tests/System/Net/WebSockets/WebSocketStream.cs b/src/libraries/Common/tests/System/Net/WebSockets/WebSocketStream.cs new file mode 100644 index 0000000000000..322f5d2a00cb0 --- /dev/null +++ b/src/libraries/Common/tests/System/Net/WebSockets/WebSocketStream.cs @@ -0,0 +1,285 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Threading.Tasks; +using System.IO; +using System.Threading; + +namespace System.Net.WebSockets +{ + public class WebSocketStream : Stream + { + // Used by the class to hold the underlying socket the stream uses. + private readonly WebSocket _streamSocket; + + // Whether the stream should dispose of the socket when the stream is disposed + private readonly bool _ownsSocket; + + // Used by the class to indicate that the stream is m_Readable. + private bool _readable; + + // Used by the class to indicate that the stream is writable. + private bool _writeable; + + // Whether Dispose has been called. 0 == false, 1 == true + private int _disposed; + + public WebSocketStream(WebSocket socket) + : this(socket, FileAccess.ReadWrite, ownsSocket: false) + { + } + + public WebSocketStream(WebSocket socket, bool ownsSocket) + : this(socket, FileAccess.ReadWrite, ownsSocket) + { + } + + public WebSocketStream(WebSocket socket, FileAccess access) + : this(socket, access, ownsSocket: false) + { + } + + public WebSocketStream(WebSocket socket, FileAccess access, bool ownsSocket) + { + if (socket == null) + { + throw new ArgumentNullException(nameof(socket)); + } + if (socket.State != WebSocketState.Open) + { + throw new IOException("The operation is not allowed on non-connected sockets."); + } + + _streamSocket = socket; + _ownsSocket = ownsSocket; + + switch (access) + { + case FileAccess.Read: + _readable = true; + break; + case FileAccess.Write: + _writeable = true; + break; + case FileAccess.ReadWrite: + default: // assume FileAccess.ReadWrite + _readable = true; + _writeable = true; + break; + } + } + + public WebSocket Socket => _streamSocket; + + protected bool Readable + { + get { return _readable; } + set { _readable = value; } + } + + protected bool Writeable + { + get { return _writeable; } + set { _writeable = value; } + } + + public override bool CanRead => _readable; + public override bool CanSeek => false; + public override bool CanWrite => _writeable; + public override bool CanTimeout => true; + public override long Length => throw new NotSupportedException("This stream does not support seek operations."); + + public override long Position + { + get + { + throw new NotSupportedException("This stream does not support seek operations."); + } + set + { + throw new NotSupportedException("This stream does not support seek operations."); + } + } + + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotSupportedException("This stream does not support seek operations."); + } + + public override int Read(byte[] buffer, int offset, int count) + { + throw new IOException("The operation is not allowed on a non-blocking Socket."); + } + + public override int Read(Span buffer) + { + throw new IOException("The operation is not allowed on a non-blocking Socket."); + } + + public override void Write(byte[] buffer, int offset, int count) + { + throw new IOException("The operation is not allowed on a non-blocking Socket."); + } + + public override void Write(ReadOnlySpan buffer) + { + throw new IOException("The operation is not allowed on a non-blocking Socket."); + } + + private int _closeTimeout = -1; + + public void Close(int timeout) + { + if (timeout < -1) + { + throw new ArgumentOutOfRangeException(nameof(timeout)); + } + _closeTimeout = timeout; + Dispose(); + } + + protected override void Dispose(bool disposing) + { + if (Interlocked.Exchange(ref _disposed, 1) != 0) + { + return; + } + + if (disposing) + { + _readable = false; + _writeable = false; + if (_ownsSocket) + { + if (_streamSocket != null && (_streamSocket.State == WebSocketState.Open || _streamSocket.State == WebSocketState.Connecting || _streamSocket.State == WebSocketState.None)) + { + try + { + var task = _streamSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "closing remoteLoop", CancellationToken.None); + Task.WaitAll(task); + } + catch (Exception) + { + } + finally + { + _streamSocket.Dispose(); + } + } + } + } + + base.Dispose(disposing); + } + + ~WebSocketStream() => Dispose(false); + + public async override Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) + { + ValidateBufferArguments(buffer, offset, count); + ThrowIfDisposed(); + if (!CanRead) + { + throw new InvalidOperationException("The stream does not support reading."); + } + + try + { + var res = await _streamSocket.ReceiveAsync(new Memory(buffer, offset, count), cancellationToken); + return res.Count; + } + catch (Exception exception) when (!(exception is OutOfMemoryException)) + { + throw WrapException("Unable to read data from the transport connection", exception); + } + } + + public async override ValueTask ReadAsync(Memory buffer, CancellationToken cancellationToken) + { + bool canRead = CanRead; // Prevent race with Dispose. + ThrowIfDisposed(); + if (!canRead) + { + throw new InvalidOperationException("The stream does not support reading."); + } + + try + { + var res = await _streamSocket.ReceiveAsync(buffer, + cancellationToken); + return res.Count; + } + catch (Exception exception) when (!(exception is OutOfMemoryException)) + { + throw WrapException("Unable to read data from the transport connection", exception); + } + } + + public async override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) + { + ValidateBufferArguments(buffer, offset, count); + ThrowIfDisposed(); + if (!CanWrite) + { + throw new InvalidOperationException("The stream does not support writing."); + } + + try + { + await _streamSocket.SendAsync(new ReadOnlyMemory(buffer, offset, count), WebSocketMessageType.Binary, true, cancellationToken); + } + catch (Exception exception) when (!(exception is OutOfMemoryException)) + { + throw WrapException("Unable to write data to the transport connection", exception); + } + } + + public async override ValueTask WriteAsync(ReadOnlyMemory buffer, CancellationToken cancellationToken) + { + bool canWrite = CanWrite; // Prevent race with Dispose. + ThrowIfDisposed(); + if (!canWrite) + { + throw new InvalidOperationException("The stream does not support writing."); + } + + try + { + await _streamSocket.SendAsync(buffer, WebSocketMessageType.Binary, true, cancellationToken); + } + catch (Exception exception) when (!(exception is OutOfMemoryException)) + { + throw WrapException("Unable to write data to the transport connection", exception); + } + } + + public override void Flush() + { + } + + public override Task FlushAsync(CancellationToken cancellationToken) + { + return Task.CompletedTask; + } + + public override void SetLength(long value) + { + throw new NotSupportedException("This stream does not support seek operations."); + } + + private void ThrowIfDisposed() + { + if (_disposed != 0) + { + ThrowObjectDisposedException(); + } + + void ThrowObjectDisposedException() => throw new ObjectDisposedException(GetType().FullName); + } + + private static IOException WrapException(string resourceFormatString, Exception innerException) + { + return new IOException(resourceFormatString, innerException); + } + } +} diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.AltSvc.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.AltSvc.cs index 76d80f21450af..6cb8bbc075c2b 100644 --- a/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.AltSvc.cs +++ b/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.AltSvc.cs @@ -41,7 +41,7 @@ public async Task AltSvc_Header_Upgrade_Success(Version fromVersion, bool overri using GenericLoopbackServer firstServer = fromVersion.Major switch { - 1 => new LoopbackServer(new LoopbackServer.Options { UseSsl = true }), + 1 => Http11LoopbackServerFactory.Singleton.CreateServer(new LoopbackServer.Options { UseSsl = true }), 2 => Http2LoopbackServer.CreateServer(), _ => throw new Exception("Unknown HTTP version.") }; diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Headers.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Headers.cs index 73a543ac12a21..7a1ceaf88c792 100644 --- a/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Headers.cs +++ b/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Headers.cs @@ -23,7 +23,6 @@ public HttpClientHandlerTest_Headers(ITestOutputHelper output) : base(output) { private sealed class DerivedHttpHeaders : HttpHeaders { } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/42852", TestPlatforms.Browser)] public async Task SendAsync_RequestWithSimpleHeader_ResponseReferencesUnmodifiedRequestHeaders() { const string HeaderKey = "some-header-123", HeaderValue = "this is the expected header value"; @@ -47,7 +46,7 @@ await LoopbackServerFactory.CreateClientAndServerAsync(async uri => } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/42852", TestPlatforms.Browser)] + [SkipOnPlatform(TestPlatforms.Browser, "User-Agent is not supported on Browser")] public async Task SendAsync_UserAgent_CorrectlyWritten() { string userAgent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.18 Safari/537.36"; @@ -71,7 +70,6 @@ await LoopbackServerFactory.CreateClientAndServerAsync(async uri => } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/42852", TestPlatforms.Browser)] public async Task SendAsync_LargeHeaders_CorrectlyWritten() { if (UseVersion == HttpVersion.Version30) @@ -107,7 +105,6 @@ await LoopbackServerFactory.CreateClientAndServerAsync(async uri => } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/42852", TestPlatforms.Browser)] public async Task SendAsync_DefaultHeaders_CorrectlyWritten() { const string Version = "2017-04-17"; @@ -137,7 +134,7 @@ await LoopbackServerFactory.CreateClientAndServerAsync(async uri => [Theory] [InlineData("\u05D1\u05F1")] [InlineData("jp\u30A5")] - [ActiveIssue("https://github.com/dotnet/runtime/issues/42852", TestPlatforms.Browser)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/54160", TestPlatforms.Browser)] public async Task SendAsync_InvalidCharactersInHeader_Throw(string value) { await LoopbackServerFactory.CreateClientAndServerAsync(async uri => @@ -169,9 +166,14 @@ await LoopbackServerFactory.CreateClientAndServerAsync(async uri => [InlineData("Accept-CharSet", "text/plain, text/json", false)] // invalid format for header but added with TryAddWithoutValidation [InlineData("Content-Location", "", false)] // invalid format for header but added with TryAddWithoutValidation [InlineData("Max-Forwards", "NotAnInteger", false)] // invalid format for header but added with TryAddWithoutValidation - [ActiveIssue("https://github.com/dotnet/runtime/issues/42852", TestPlatforms.Browser)] public async Task SendAsync_SpecialHeaderKeyOrValue_Success(string key, string value, bool parsable) { + if (PlatformDetection.IsBrowser && (key == "Content-Location" || key == "Date" || key == "Accept-CharSet")) + { + // https://fetch.spec.whatwg.org/#forbidden-header-name + return; + } + await LoopbackServerFactory.CreateClientAndServerAsync(async uri => { bool contentHeader = false; @@ -209,7 +211,6 @@ await LoopbackServerFactory.CreateClientAndServerAsync(async uri => [Theory] [InlineData("Content-Security-Policy", 4618)] [InlineData("RandomCustomHeader", 12345)] - [ActiveIssue("https://github.com/dotnet/runtime/issues/42852", TestPlatforms.Browser)] public async Task GetAsync_LargeHeader_Success(string headerName, int headerValueLength) { var rand = new Random(42); @@ -234,7 +235,6 @@ await LoopbackServerFactory.CreateClientAndServerAsync(async uri => } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/42852", TestPlatforms.Browser)] public async Task GetAsync_EmptyResponseHeader_Success() { IList headers = new HttpHeaderData[] { @@ -246,8 +246,12 @@ await LoopbackServerFactory.CreateClientAndServerAsync(async uri => { using (HttpClient client = CreateHttpClient()) { - HttpResponseMessage response = await client.GetAsync(uri).ConfigureAwait(false); - Assert.Equal(headers.Count, response.Headers.Count()); + HttpResponseMessage response = await client.GetAsync(uri).ConfigureAwait(false); + // browser sends more headers + if (PlatformDetection.IsNotBrowser) + { + Assert.Equal(headers.Count, response.Headers.Count()); + } Assert.NotNull(response.Headers.GetValues("x-empty")); } }, @@ -262,7 +266,6 @@ await server.AcceptConnectionAsync(async connection => } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/42852", TestPlatforms.Browser)] public async Task GetAsync_MissingExpires_ReturnNull() { await LoopbackServerFactory.CreateClientAndServerAsync(async uri => @@ -283,7 +286,6 @@ await LoopbackServerFactory.CreateClientAndServerAsync(async uri => [InlineData("Thu, 01 Dec 1994 16:00:00 GMT", true)] [InlineData("-1", false)] [InlineData("0", false)] - [ActiveIssue("https://github.com/dotnet/runtime/issues/42852", TestPlatforms.Browser)] public async Task SendAsync_Expires_Success(string value, bool isValid) { await LoopbackServerFactory.CreateClientAndServerAsync(async uri => @@ -322,7 +324,6 @@ public void HeadersAdd_CustomExpires_Success(string value, bool isValid) [Theory] [InlineData("Accept-Encoding", "identity,gzip")] - [ActiveIssue("https://github.com/dotnet/runtime/issues/42852", TestPlatforms.Browser)] public async Task SendAsync_RequestHeaderInResponse_Success(string name, string value) { await LoopbackServerFactory.CreateClientAndServerAsync(async uri => @@ -400,7 +401,7 @@ public async Task SendAsync_GetWithInvalidHostHeader_ThrowsException() } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/42852", TestPlatforms.Browser)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/54160", TestPlatforms.Browser)] public async Task SendAsync_WithZeroLengthHeaderName_Throws() { await LoopbackServerFactory.CreateClientAndServerAsync( @@ -443,7 +444,7 @@ private static readonly (string Name, Encoding ValueEncoding, string[] Values)[] }; [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/42852", TestPlatforms.Browser)] + [SkipOnPlatform(TestPlatforms.Browser, "Socket is not supported on Browser")] public async Task SendAsync_CustomRequestEncodingSelector_CanSendNonAsciiHeaderValues() { await LoopbackServerFactory.CreateClientAndServerAsync( @@ -498,7 +499,7 @@ await LoopbackServerFactory.CreateClientAndServerAsync( } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/42852", TestPlatforms.Browser)] + [SkipOnPlatform(TestPlatforms.Browser, "Socket is not supported on Browser")] public async Task SendAsync_CustomResponseEncodingSelector_CanReceiveNonAsciiHeaderValues() { await LoopbackServerFactory.CreateClientAndServerAsync( diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Http1.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Http1.cs index c7579cd114bb2..f0e58b32ca345 100644 --- a/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Http1.cs +++ b/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Http1.cs @@ -17,7 +17,6 @@ public class HttpClientHandlerTest_Http1 : HttpClientHandlerTestBase public HttpClientHandlerTest_Http1(ITestOutputHelper output) : base(output) { } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/39187", TestPlatforms.Browser)] public async Task SendAsync_HostHeader_First() { // RFC 7230 3.2.2. Field Order diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.RequestRetry.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.RequestRetry.cs index ced259294f8c1..4e2426b958e65 100644 --- a/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.RequestRetry.cs +++ b/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.RequestRetry.cs @@ -19,7 +19,6 @@ public abstract class HttpClientHandlerTest_RequestRetry : HttpClientHandlerTest public HttpClientHandlerTest_RequestRetry(ITestOutputHelper output) : base(output) { } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/42852", TestPlatforms.Browser)] public async Task GetAsyncOnNewConnection_RetryOnConnectionClosed_Success() { await LoopbackServer.CreateClientAndServerAsync(async url => diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientMiniStressTest.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientMiniStressTest.cs index 6d68042a73316..af3bdd764bc72 100644 --- a/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientMiniStressTest.cs +++ b/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientMiniStressTest.cs @@ -98,6 +98,7 @@ await server.AcceptConnectionAsync(async connection => } [Collection(nameof(HttpClientMiniStress))] + [SkipOnPlatform(TestPlatforms.Browser, "System.Net.Security is not supported on Browser")] public abstract class HttpClientMiniStress : HttpClientHandlerTestBase { public HttpClientMiniStress(ITestOutputHelper output) : base(output) { } diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientTest.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientTest.cs index 94d59d89b03ff..451bb20d58fa1 100644 --- a/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientTest.cs +++ b/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientTest.cs @@ -357,8 +357,6 @@ public async Task GetAsync_CustomException_Asynchronous_ThrowsException() } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/39187", TestPlatforms.Browser)] - [ActiveIssue("https://github.com/dotnet/runtime/issues/42852", TestPlatforms.Browser)] public async Task GetStringAsync_Success() { string content = Guid.NewGuid().ToString(); @@ -378,8 +376,7 @@ await LoopbackServer.CreateClientAndServerAsync( } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/39187", TestPlatforms.Browser)] - [ActiveIssue("https://github.com/dotnet/runtime/issues/42852", TestPlatforms.Browser)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/54270", TestPlatforms.Browser)] public async Task GetStringAsync_CanBeCanceled_AlreadyCanceledCts() { var onClientFinished = new SemaphoreSlim(0, 1); @@ -404,8 +401,7 @@ await LoopbackServer.CreateClientAndServerAsync( } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/39187", TestPlatforms.Browser)] - [ActiveIssue("https://github.com/dotnet/runtime/issues/42852", TestPlatforms.Browser)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/54270", TestPlatforms.Browser)] public async Task GetStringAsync_CanBeCanceled() { var cts = new CancellationTokenSource(); @@ -440,7 +436,7 @@ await server.AcceptConnectionAsync(async connection => [InlineData(1, 0)] [InlineData(1, 1)] [InlineData(1, 2)] - [ActiveIssue("https://github.com/dotnet/runtime/issues/42852", TestPlatforms.Browser)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/54270", TestPlatforms.Browser)] public async Task GetAsync_ContentCanBeCanceled(int getMode, int cancelMode) { // cancelMode: @@ -530,8 +526,6 @@ await LoopbackServerFactory.CreateClientAndServerAsync( } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/39187", TestPlatforms.Browser)] - [ActiveIssue("https://github.com/dotnet/runtime/issues/42852", TestPlatforms.Browser)] public async Task GetByteArrayAsync_Success() { string content = Guid.NewGuid().ToString(); @@ -552,8 +546,7 @@ await LoopbackServer.CreateClientAndServerAsync( } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/39187", TestPlatforms.Browser)] - [ActiveIssue("https://github.com/dotnet/runtime/issues/42852", TestPlatforms.Browser)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/54270", TestPlatforms.Browser)] public async Task GetByteArrayAsync_CanBeCanceled_AlreadyCanceledCts() { var onClientFinished = new SemaphoreSlim(0, 1); @@ -578,8 +571,7 @@ await LoopbackServer.CreateClientAndServerAsync( } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/39187", TestPlatforms.Browser)] - [ActiveIssue("https://github.com/dotnet/runtime/issues/42852", TestPlatforms.Browser)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/54270", TestPlatforms.Browser)] public async Task GetByteArrayAsync_CanBeCanceled() { var cts = new CancellationTokenSource(); @@ -607,8 +599,6 @@ await server.AcceptConnectionAsync(async connection => } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/39187", TestPlatforms.Browser)] - [ActiveIssue("https://github.com/dotnet/runtime/issues/42852", TestPlatforms.Browser)] public async Task GetStreamAsync_Success() { string content = Guid.NewGuid().ToString(); @@ -632,8 +622,7 @@ await LoopbackServer.CreateClientAndServerAsync( } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/39187", TestPlatforms.Browser)] - [ActiveIssue("https://github.com/dotnet/runtime/issues/42852", TestPlatforms.Browser)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/54270", TestPlatforms.Browser)] public async Task GetStreamAsync_CanBeCanceled_AlreadyCanceledCts() { var onClientFinished = new SemaphoreSlim(0, 1); @@ -658,8 +647,7 @@ await LoopbackServer.CreateClientAndServerAsync( } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/39187", TestPlatforms.Browser)] - [ActiveIssue("https://github.com/dotnet/runtime/issues/42852", TestPlatforms.Browser)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/54270", TestPlatforms.Browser)] public async Task GetStreamAsync_CanBeCanceled() { var cts = new CancellationTokenSource(); @@ -916,8 +904,7 @@ public void Send_SingleThread_Succeeds(HttpCompletionOption completionOption) [Theory] [InlineData(HttpCompletionOption.ResponseContentRead)] [InlineData(HttpCompletionOption.ResponseHeadersRead)] - [ActiveIssue("https://github.com/dotnet/runtime/issues/39187", TestPlatforms.Browser)] - [ActiveIssue("https://github.com/dotnet/runtime/issues/42852", TestPlatforms.Browser)] + [SkipOnPlatform(TestPlatforms.Browser, "Synchronous Send is not supported on Browser")] public async Task Send_SingleThread_Loopback_Succeeds(HttpCompletionOption completionOption) { string content = "Test content"; @@ -970,7 +957,7 @@ await server.AcceptConnectionAsync(async connection => [Fact] [OuterLoop] - [ActiveIssue("https://github.com/dotnet/runtime/issues/42852", TestPlatforms.Browser)] + [SkipOnPlatform(TestPlatforms.Browser, "Synchronous Send is not supported on Browser")] public async Task Send_CancelledRequestContent_Throws() { CancellationTokenSource cts = new CancellationTokenSource(); @@ -1017,7 +1004,6 @@ await server.AcceptConnectionAsync(async connection => [Fact] [OuterLoop] [ActiveIssue("https://github.com/dotnet/runtime/issues/39056")] - [ActiveIssue("https://github.com/dotnet/runtime/issues/42852", TestPlatforms.Browser)] public async Task Send_TimeoutRequestContent_Throws() { await LoopbackServer.CreateClientAndServerAsync( @@ -1060,7 +1046,7 @@ await server.AcceptConnectionAsync(async connection => [Fact] [OuterLoop] - [ActiveIssue("https://github.com/dotnet/runtime/issues/42852", TestPlatforms.Browser)] + [SkipOnPlatform(TestPlatforms.Browser, "Synchronous Send is not supported on Browser")] public async Task Send_CancelledResponseContent_Throws() { string content = "Test content"; @@ -1110,12 +1096,13 @@ await server.AcceptConnectionAsync(async connection => [Fact] [OuterLoop] - [ActiveIssue("https://github.com/dotnet/runtime/issues/42852", TestPlatforms.Browser)] - public void Send_TimeoutResponseContent_Throws() + [SkipOnPlatform(TestPlatforms.Browser, "Synchronous Send is not supported on Browser")] + public async Task Send_TimeoutResponseContent_Throws() { const string Content = "Test content"; using var server = new LoopbackServer(); + await server.ListenAsync(); // Ignore all failures from the server. This includes being disposed of before ever accepting a connection, // which is possible if the client times out so quickly that it hasn't initiated a connection yet. @@ -1163,8 +1150,7 @@ public static IEnumerable VersionSelectionMemberData() [Theory] [MemberData(nameof(VersionSelectionMemberData))] - [ActiveIssue("https://github.com/dotnet/runtime/issues/39187", TestPlatforms.Browser)] - [ActiveIssue("https://github.com/dotnet/runtime/issues/42852", TestPlatforms.Browser)] + [SkipOnPlatform(TestPlatforms.Browser, "Version is ignored on Browser")] public async Task SendAsync_CorrectVersionSelected_LoopbackServer(Version requestVersion, HttpVersionPolicy versionPolicy, Version serverVersion, bool useSsl, object expectedResult) { await HttpAgnosticLoopbackServer.CreateClientAndServerAsync( diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/HttpContentTest.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/HttpContentTest.cs index 214042a185040..b09b0d2dc1a38 100644 --- a/src/libraries/System.Net.Http/tests/FunctionalTests/HttpContentTest.cs +++ b/src/libraries/System.Net.Http/tests/FunctionalTests/HttpContentTest.cs @@ -613,8 +613,6 @@ public void Dispose_DisposedObjectThenAccessMembers_ThrowsObjectDisposedExceptio [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/39187", TestPlatforms.Browser)] - [ActiveIssue("https://github.com/dotnet/runtime/issues/42852", TestPlatforms.Browser)] public async Task ReadAsStringAsync_Buffered_IgnoresCancellationToken() { string content = Guid.NewGuid().ToString(); @@ -641,8 +639,6 @@ await LoopbackServer.CreateClientAndServerAsync( } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/39187", TestPlatforms.Browser)] - [ActiveIssue("https://github.com/dotnet/runtime/issues/42852", TestPlatforms.Browser)] public async Task ReadAsStringAsync_Unbuffered_CanBeCanceled_AlreadyCanceledCts() { await LoopbackServer.CreateClientAndServerAsync( @@ -670,8 +666,6 @@ await LoopbackServer.CreateClientAndServerAsync( } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/39187", TestPlatforms.Browser)] - [ActiveIssue("https://github.com/dotnet/runtime/issues/42852", TestPlatforms.Browser)] public async Task ReadAsStringAsync_Unbuffered_CanBeCanceled() { var cts = new CancellationTokenSource(); @@ -706,8 +700,6 @@ await server.AcceptConnectionAsync(async connection => } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/39187", TestPlatforms.Browser)] - [ActiveIssue("https://github.com/dotnet/runtime/issues/42852", TestPlatforms.Browser)] public async Task ReadAsByteArrayAsync_Buffered_IgnoresCancellationToken() { string content = Guid.NewGuid().ToString(); @@ -735,8 +727,6 @@ await LoopbackServer.CreateClientAndServerAsync( } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/39187", TestPlatforms.Browser)] - [ActiveIssue("https://github.com/dotnet/runtime/issues/42852", TestPlatforms.Browser)] public async Task ReadAsByteArrayAsync_Unbuffered_CanBeCanceled_AlreadyCanceledCts() { await LoopbackServer.CreateClientAndServerAsync( @@ -764,8 +754,6 @@ await LoopbackServer.CreateClientAndServerAsync( } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/39187", TestPlatforms.Browser)] - [ActiveIssue("https://github.com/dotnet/runtime/issues/42852", TestPlatforms.Browser)] public async Task ReadAsByteArrayAsync_Unbuffered_CanBeCanceled() { var cts = new CancellationTokenSource(); @@ -802,8 +790,6 @@ await server.AcceptConnectionAsync(async connection => [Theory] [InlineData(true)] [InlineData(false)] - [ActiveIssue("https://github.com/dotnet/runtime/issues/39187", TestPlatforms.Browser)] - [ActiveIssue("https://github.com/dotnet/runtime/issues/42852", TestPlatforms.Browser)] public async Task ReadAsStreamAsync_Buffered_IgnoresCancellationToken(bool readStreamAsync) { string content = Guid.NewGuid().ToString(); @@ -835,10 +821,13 @@ await LoopbackServer.CreateClientAndServerAsync( [Theory] [InlineData(true)] [InlineData(false)] - [ActiveIssue("https://github.com/dotnet/runtime/issues/39187", TestPlatforms.Browser)] - [ActiveIssue("https://github.com/dotnet/runtime/issues/42852", TestPlatforms.Browser)] public async Task ReadAsStreamAsync_Unbuffered_IgnoresCancellationToken(bool readStreamAsync) { + if(PlatformDetection.IsBrowser && !readStreamAsync) + { + // syncronous operations are not supported on Browser + return; + } string content = Guid.NewGuid().ToString(); await LoopbackServer.CreateClientAndServerAsync( diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/HttpRequestMessageTest.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/HttpRequestMessageTest.cs index 167d5a0504c96..18b7fa9fe47cc 100644 --- a/src/libraries/System.Net.Http/tests/FunctionalTests/HttpRequestMessageTest.cs +++ b/src/libraries/System.Net.Http/tests/FunctionalTests/HttpRequestMessageTest.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.IO; +using System.Linq; using System.Net.Http.Headers; using System.Net.Test.Common; using System.Threading.Tasks; @@ -12,7 +13,6 @@ namespace System.Net.Http.Functional.Tests { - [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] public class HttpRequestMessageTest : HttpClientHandlerTestBase { private readonly Version _expectedRequestMessageVersion = HttpVersion.Version11; @@ -240,8 +240,12 @@ await LoopbackServer.CreateServerAsync(async (server, uri) => Task requestTask = client.SendAsync(request); await server.AcceptConnectionAsync(async connection => { - List headers = await connection.ReadRequestHeaderAsync(); - Assert.DoesNotContain(headers, line => line.StartsWith("Content-length")); + var requestData = await connection.ReadRequestDataAsync().ConfigureAwait(false); +#if TARGET_BROWSER + requestData = await connection.HandleCORSPreFlight(requestData); +#endif + + Assert.DoesNotContain(requestData.Headers, line => line.Name.StartsWith("Content-length")); await connection.SendResponseAsync(); await requestTask; diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/SocketsHttpHandlerTest.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/SocketsHttpHandlerTest.cs index 0ac38b257277f..cf7edc9881413 100644 --- a/src/libraries/System.Net.Http/tests/FunctionalTests/SocketsHttpHandlerTest.cs +++ b/src/libraries/System.Net.Http/tests/FunctionalTests/SocketsHttpHandlerTest.cs @@ -170,19 +170,19 @@ public sealed class SocketsHttpHandler_HttpClientHandler_Decompression_Tests : H public SocketsHttpHandler_HttpClientHandler_Decompression_Tests(ITestOutputHelper output) : base(output) { } } - [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [SkipOnPlatform(TestPlatforms.Browser, "Certificates are not supported on Browser")] public sealed class SocketsHttpHandler_HttpClientHandler_DangerousAcceptAllCertificatesValidator_Test : HttpClientHandler_DangerousAcceptAllCertificatesValidator_Test { public SocketsHttpHandler_HttpClientHandler_DangerousAcceptAllCertificatesValidator_Test(ITestOutputHelper output) : base(output) { } } - [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [SkipOnPlatform(TestPlatforms.Browser, "Certificates are not supported on Browser")] public sealed class SocketsHttpHandler_HttpClientHandler_ClientCertificates_Test : HttpClientHandler_ClientCertificates_Test { public SocketsHttpHandler_HttpClientHandler_ClientCertificates_Test(ITestOutputHelper output) : base(output) { } } - [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [SkipOnPlatform(TestPlatforms.Browser, "Proxy is not supported on Browser")] public sealed class SocketsHttpHandler_HttpClientHandler_DefaultProxyCredentials_Test : HttpClientHandler_DefaultProxyCredentials_Test { public SocketsHttpHandler_HttpClientHandler_DefaultProxyCredentials_Test(ITestOutputHelper output) : base(output) { } @@ -248,13 +248,13 @@ await server.AcceptConnectionAsync(async connection => } } - [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [SkipOnPlatform(TestPlatforms.Browser, "Certificates are not supported on Browser")] public sealed class SocketsHttpHandler_HttpClientHandler_ServerCertificates_Test : HttpClientHandler_ServerCertificates_Test { public SocketsHttpHandler_HttpClientHandler_ServerCertificates_Test(ITestOutputHelper output) : base(output) { } } - [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [SkipOnPlatform(TestPlatforms.Browser, "ResponseDrainTimeout is not supported on Browser")] public sealed class SocketsHttpHandler_HttpClientHandler_ResponseDrain_Test : HttpClientHandler_ResponseDrain_Test { protected override void SetResponseDrainTimeout(HttpClientHandler handler, TimeSpan time) @@ -560,13 +560,13 @@ public sealed class SocketsHttpHandler_ResponseStreamTest : ResponseStreamTest public SocketsHttpHandler_ResponseStreamTest(ITestOutputHelper output) : base(output) { } } - [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [ActiveIssue("https://github.com/dotnet/runtime/issues/37669", TestPlatforms.Browser)] public sealed class SocketsHttpHandler_HttpClientHandler_SslProtocols_Test : HttpClientHandler_SslProtocols_Test { public SocketsHttpHandler_HttpClientHandler_SslProtocols_Test(ITestOutputHelper output) : base(output) { } } - [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [SkipOnPlatform(TestPlatforms.Browser, "UseProxy not supported on Browser")] public sealed class SocketsHttpHandler_HttpClientHandler_Proxy_Test : HttpClientHandler_Proxy_Test { public SocketsHttpHandler_HttpClientHandler_Proxy_Test(ITestOutputHelper output) : base(output) { } @@ -588,8 +588,7 @@ protected static Frame MakeDataFrame(int streamId, byte[] data, bool endStream = new DataFrame(data, (endStream ? FrameFlags.EndStream : FrameFlags.None), 0, streamId); } - // System.Net.Sockets is not supported on this platform - [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [ActiveIssue("https://github.com/dotnet/runtime/issues/54156", TestPlatforms.Browser)] public class SocketsHttpHandler_Http1_TrailingHeaders_Test : SocketsHttpHandler_TrailingHeaders_Test { public SocketsHttpHandler_Http1_TrailingHeaders_Test(ITestOutputHelper output) : base(output) { } @@ -609,6 +608,7 @@ await TestHelper.WhenAllCompletedOrAnyFailed( getResponseTask, server.AcceptConnectionSendCustomResponseAndCloseAsync( "HTTP/1.1 200 OK\r\n" + + LoopbackServer.CorsHeaders + "Connection: close\r\n" + "Transfer-Encoding: chunked\r\n" + (includeTrailerHeader ? "Trailer: MyCoolTrailerHeader, Hello\r\n" : "") + @@ -662,6 +662,7 @@ await TestHelper.WhenAllCompletedOrAnyFailed( getResponseTask, server.AcceptConnectionSendCustomResponseAndCloseAsync( "HTTP/1.1 200 OK\r\n" + + LoopbackServer.CorsHeaders + "Connection: close\r\n" + "Transfer-Encoding: chunked\r\n" + "Trailer: MyCoolTrailerHeader\r\n" + @@ -751,6 +752,7 @@ await LoopbackServer.CreateClientAndServerAsync(async url => } }, server => server.AcceptConnectionSendCustomResponseAndCloseAsync( "HTTP/1.1 200 OK\r\n" + + LoopbackServer.CorsHeaders + "Connection: close\r\n" + "Transfer-Encoding: chunked\r\n" + $"Trailer: Set-Cookie, MyCoolTrailerHeader, {name}, Hello\r\n" + @@ -780,6 +782,7 @@ await TestHelper.WhenAllCompletedOrAnyFailed( server.AcceptConnectionSendCustomResponseAndCloseAsync( "HTTP/1.1 200 OK\r\n" + "Connection: close\r\n" + + LoopbackServer.CorsHeaders + "Transfer-Encoding: chunked\r\n" + "Trailer: MyCoolTrailerHeader\r\n" + "\r\n" + @@ -987,7 +990,6 @@ public sealed class SocketsHttpHandler_SchSendAuxRecordHttpTest : SchSendAuxReco public SocketsHttpHandler_SchSendAuxRecordHttpTest(ITestOutputHelper output) : base(output) { } } - [SkipOnPlatform(TestPlatforms.Browser, "Tests hang with chrome. To be investigated")] public sealed class SocketsHttpHandler_HttpClientHandlerTest : HttpClientHandlerTest { public SocketsHttpHandler_HttpClientHandlerTest(ITestOutputHelper output) : base(output) { } @@ -1017,19 +1019,19 @@ public sealed class SocketsHttpHandlerTest_RequestRetry : HttpClientHandlerTest_ public SocketsHttpHandlerTest_RequestRetry(ITestOutputHelper output) : base(output) { } } - [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [SkipOnPlatform(TestPlatforms.Browser, "UseCookies is not supported on Browser")] public sealed class SocketsHttpHandlerTest_Cookies : HttpClientHandlerTest_Cookies { public SocketsHttpHandlerTest_Cookies(ITestOutputHelper output) : base(output) { } } - [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [SkipOnPlatform(TestPlatforms.Browser, "UseCookies is not supported on Browser")] public sealed class SocketsHttpHandlerTest_Cookies_Http11 : HttpClientHandlerTest_Cookies_Http11 { public SocketsHttpHandlerTest_Cookies_Http11(ITestOutputHelper output) : base(output) { } } - [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [SkipOnPlatform(TestPlatforms.Browser, "ConnectTimeout is not supported on Browser")] public sealed class SocketsHttpHandler_HttpClientHandler_Http11_Cancellation_Test : SocketsHttpHandler_Cancellation_Test { public SocketsHttpHandler_HttpClientHandler_Http11_Cancellation_Test(ITestOutputHelper output) : base(output) { } @@ -1130,15 +1132,13 @@ public void Expect100ContinueTimeout_SetAfterUse_Throws() } } - // BrowserHttpHandler.set_MaxResponseHeadersLength - Not supported on this platform - [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [SkipOnPlatform(TestPlatforms.Browser, "MaxResponseHeadersLength is not supported on Browser")] public sealed class SocketsHttpHandler_HttpClientHandler_MaxResponseHeadersLength_Test : HttpClientHandler_MaxResponseHeadersLength_Test { public SocketsHttpHandler_HttpClientHandler_MaxResponseHeadersLength_Test(ITestOutputHelper output) : base(output) { } } - //System.Net.Sockets is not supported on this platform - [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [SkipOnPlatform(TestPlatforms.Browser, "Socket is not supported on Browser")] public sealed class SocketsHttpHandler_HttpClientHandler_Authentication_Test : HttpClientHandler_Authentication_Test { public SocketsHttpHandler_HttpClientHandler_Authentication_Test(ITestOutputHelper output) : base(output) { } @@ -1158,7 +1158,7 @@ await LoopbackServer.CreateServerAsync(async (server, url) => { // We need to use ResponseHeadersRead here, otherwise we will hang trying to buffer the response body. Task getResponseTask = client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead); - await server.AcceptConnectionAsync(async connection => + await server.AcceptConnectionAsync(async (LoopbackServer.Connection connection) => { Task> serverTask = connection.ReadRequestHeaderAndSendCustomResponseAsync($"HTTP/1.1 101 Switching Protocols\r\nDate: {DateTimeOffset.UtcNow:R}\r\n\r\n"); @@ -1252,7 +1252,7 @@ await server.AcceptConnectionAsync(async connection => Task copyTask = clientStream.CopyToAsync(ms); string bigString = string.Concat(Enumerable.Repeat("abcdefghijklmnopqrstuvwxyz", 1000)); - Task lotsOfDataSent = connection.Socket.SendAsync(Encoding.ASCII.GetBytes(bigString), SocketFlags.None); + Task lotsOfDataSent = connection.SendResponseAsync(Encoding.ASCII.GetBytes(bigString)); connection.Socket.Shutdown(SocketShutdown.Send); await copyTask; await lotsOfDataSent; @@ -1270,8 +1270,7 @@ public sealed class SocketsHttpHandler_Connect_Test : HttpClientHandler_Connect_ public SocketsHttpHandler_Connect_Test(ITestOutputHelper output) : base(output) { } } - // System.Net.Sockets is not supported on this platform - [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [SkipOnPlatform(TestPlatforms.Browser, "Socket is not supported on Browser")] public sealed class SocketsHttpHandler_HttpClientHandler_ConnectionPooling_Test : HttpClientHandlerTestBase { public SocketsHttpHandler_HttpClientHandler_ConnectionPooling_Test(ITestOutputHelper output) : base(output) { } @@ -1468,7 +1467,7 @@ await Http2LoopbackServerFactory.CreateServerAsync(async (server, url) => // Wait a small amount of time before making the second request, to give the first request time to timeout. await Task.Delay(100); // Grab reference to underlying socket and stream to make sure they are not disposed and closed. - (Socket socket, Stream stream) = connection.ResetNetwork(); + (SocketWrapper socket, Stream stream) = connection.ResetNetwork(); // Make second request and expect it to be served from a different connection. Task request2 = client.GetStringAsync(url); @@ -1997,8 +1996,7 @@ await Assert.ThrowsAnyAsync(() => } } - // System.Net.Sockets is not supported on this platform - [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [SkipOnPlatform(TestPlatforms.Browser, "Headers.Location are not supported on Browser")] public sealed class SocketsHttpHandlerTest_LocationHeader { private static readonly byte[] s_redirectResponseBefore = Encoding.ASCII.GetBytes( @@ -2671,8 +2669,7 @@ public async Task ConnectCallback_ReturnsNull_ThrowsHttpRequestException(bool us private static bool PlatformSupportsUnixDomainSockets => Socket.OSSupportsUnixDomainSockets; } - // System.Net.Sockets is not supported on this platform - [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [SkipOnPlatform(TestPlatforms.Browser, "Socket is not supported on Browser")] public sealed class SocketsHttpHandlerTest_ConnectCallback_Http11 : SocketsHttpHandlerTest_ConnectCallback { public SocketsHttpHandlerTest_ConnectCallback_Http11(ITestOutputHelper output) : base(output) { } diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/SocksProxyTest.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/SocksProxyTest.cs index 633f562c9491b..821794e9f82d5 100644 --- a/src/libraries/System.Net.Http/tests/FunctionalTests/SocksProxyTest.cs +++ b/src/libraries/System.Net.Http/tests/FunctionalTests/SocksProxyTest.cs @@ -113,14 +113,14 @@ public async Task TestExceptionalAsync(string scheme, string host, bool useAuth, } - [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [SkipOnPlatform(TestPlatforms.Browser, "UseProxy not supported on Browser")] public sealed class SocksProxyTest_Http1_Async : SocksProxyTest { public SocksProxyTest_Http1_Async(ITestOutputHelper helper) : base(helper) { } protected override Version UseVersion => HttpVersion.Version11; } - [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [SkipOnPlatform(TestPlatforms.Browser, "UseProxy not supported on Browser")] public sealed class SocksProxyTest_Http1_Sync : SocksProxyTest { public SocksProxyTest_Http1_Sync(ITestOutputHelper helper) : base(helper) { } @@ -128,7 +128,7 @@ public SocksProxyTest_Http1_Sync(ITestOutputHelper helper) : base(helper) { } protected override bool TestAsync => false; } - [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [SkipOnPlatform(TestPlatforms.Browser, "UseProxy not supported on Browser")] public sealed class SocksProxyTest_Http2 : SocksProxyTest { public SocksProxyTest_Http2(ITestOutputHelper helper) : base(helper) { } diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj b/src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj index 7c9b9d6d15738..672ce364f7061 100644 --- a/src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj +++ b/src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj @@ -13,12 +13,17 @@ WasmTestOnBrowser $(TestArchiveRoot)browseronly/ $(TestArchiveTestsRoot)$(OSPlatformConfig)/ + $(DefineConstants);TARGET_BROWSER + + + diff --git a/src/libraries/System.Net.WebSockets.Client/tests/CloseTest.cs b/src/libraries/System.Net.WebSockets.Client/tests/CloseTest.cs index 68773696bfcdb..a10e9e4639e71 100644 --- a/src/libraries/System.Net.WebSockets.Client/tests/CloseTest.cs +++ b/src/libraries/System.Net.WebSockets.Client/tests/CloseTest.cs @@ -374,7 +374,7 @@ public async Task CloseAsync_DuringConcurrentReceiveAsync_ExpectedStates(Uri ser [ConditionalFact(nameof(WebSocketsSupported))] [ActiveIssue("https://github.com/dotnet/runtime/issues/34690", TestPlatforms.Windows, TargetFrameworkMonikers.Netcoreapp, TestRuntimes.Mono)] - [ActiveIssue("https://github.com/dotnet/runtime/issues/42852", TestPlatforms.Browser)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/54153", TestPlatforms.Browser)] public async Task CloseAsync_CancelableEvenWhenPendingReceive_Throws() { var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); diff --git a/src/libraries/System.Net.WebSockets.Client/tests/ConnectTest.cs b/src/libraries/System.Net.WebSockets.Client/tests/ConnectTest.cs index 443166cafec66..0fb1314a6068e 100644 --- a/src/libraries/System.Net.WebSockets.Client/tests/ConnectTest.cs +++ b/src/libraries/System.Net.WebSockets.Client/tests/ConnectTest.cs @@ -58,7 +58,7 @@ public async Task EchoTextMessage_Success(Uri server) [OuterLoop("Uses external servers", typeof(PlatformDetection), nameof(PlatformDetection.LocalEchoServerIsNotAvailable))] [ConditionalTheory(nameof(WebSocketsSupported)), MemberData(nameof(EchoHeadersServers))] - [SkipOnPlatform(TestPlatforms.Browser, "CustomHeaders not supported on browser")] + [SkipOnPlatform(TestPlatforms.Browser, "SetRequestHeader not supported on browser")] public async Task ConnectAsync_AddCustomHeaders_Success(Uri server) { using (var cws = new ClientWebSocket()) @@ -96,7 +96,7 @@ public async Task ConnectAsync_AddCustomHeaders_Success(Uri server) [ConditionalFact(nameof(WebSocketsSupported))] [ActiveIssue("https://github.com/dotnet/runtime/issues/34690", TestPlatforms.Windows, TargetFrameworkMonikers.Netcoreapp, TestRuntimes.Mono)] - [ActiveIssue("https://github.com/dotnet/runtime/issues/42852", TestPlatforms.Browser)] + [SkipOnPlatform(TestPlatforms.Browser, "SetRequestHeader not supported on browser")] public async Task ConnectAsync_AddHostHeader_Success() { string expectedHost = null; @@ -218,7 +218,7 @@ public async Task ConnectAsync_PassMultipleSubProtocols_ServerRequires_Connectio [ConditionalFact(nameof(WebSocketsSupported))] [ActiveIssue("https://github.com/dotnet/runtime/issues/34690", TestPlatforms.Windows, TargetFrameworkMonikers.Netcoreapp, TestRuntimes.Mono)] - [ActiveIssue("https://github.com/dotnet/runtime/issues/42852", TestPlatforms.Browser)] + [SkipOnPlatform(TestPlatforms.Browser, "SetRequestHeader not supported on Browser")] public async Task ConnectAsync_NonStandardRequestHeaders_HeadersAddedWithoutValidation() { await LoopbackServer.CreateClientAndServerAsync(async uri => @@ -237,7 +237,7 @@ await LoopbackServer.CreateClientAndServerAsync(async uri => [OuterLoop("Uses external servers", typeof(PlatformDetection), nameof(PlatformDetection.LocalEchoServerIsNotAvailable))] [ConditionalTheory(nameof(WebSocketsSupported)), MemberData(nameof(EchoServers))] - [ActiveIssue("https://github.com/dotnet/runtime/issues/42852", TestPlatforms.Browser)] + [SkipOnPlatform(TestPlatforms.Browser, "Proxy not supported on Browser")] public async Task ConnectAndCloseAsync_UseProxyServer_ExpectedClosedState(Uri server) { using (var cws = new ClientWebSocket()) @@ -282,7 +282,7 @@ public async Task ConnectAsync_CancellationRequestedInflightConnect_ThrowsOperat [ConditionalFact(nameof(WebSocketsSupported))] [ActiveIssue("https://github.com/dotnet/runtime/issues/34690", TestPlatforms.Windows, TargetFrameworkMonikers.Netcoreapp, TestRuntimes.Mono)] - [ActiveIssue("https://github.com/dotnet/runtime/issues/42852", TestPlatforms.Browser)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/54152", TestPlatforms.Browser)] public async Task ConnectAsync_CancellationRequestedAfterConnect_ThrowsOperationCanceledException() { var releaseServer = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); diff --git a/src/libraries/System.Net.WebSockets.Client/tests/DeflateTests.cs b/src/libraries/System.Net.WebSockets.Client/tests/DeflateTests.cs index 1f12d76743357..e0a0e1e59fd84 100644 --- a/src/libraries/System.Net.WebSockets.Client/tests/DeflateTests.cs +++ b/src/libraries/System.Net.WebSockets.Client/tests/DeflateTests.cs @@ -22,7 +22,6 @@ public DeflateTests(ITestOutputHelper output) : base(output) [ConditionalTheory(nameof(WebSocketsSupported))] [ActiveIssue("https://github.com/dotnet/runtime/issues/34690", TestPlatforms.Windows, TargetFrameworkMonikers.Netcoreapp, TestRuntimes.Mono)] - [ActiveIssue("https://github.com/dotnet/runtime/issues/42852", TestPlatforms.Browser)] [InlineData(15, true, 15, true, "permessage-deflate; client_max_window_bits")] [InlineData(14, true, 15, true, "permessage-deflate; client_max_window_bits=14")] [InlineData(15, true, 14, true, "permessage-deflate; client_max_window_bits; server_max_window_bits=14")] diff --git a/src/libraries/System.Net.WebSockets.Client/tests/SendReceiveTest.cs b/src/libraries/System.Net.WebSockets.Client/tests/SendReceiveTest.cs index d3a04bdbeef96..6266f01e8ede5 100644 --- a/src/libraries/System.Net.WebSockets.Client/tests/SendReceiveTest.cs +++ b/src/libraries/System.Net.WebSockets.Client/tests/SendReceiveTest.cs @@ -389,7 +389,7 @@ public async Task SendReceive_Concurrent_Success(Uri server) [OuterLoop("Uses external servers", typeof(PlatformDetection), nameof(PlatformDetection.LocalEchoServerIsNotAvailable))] [ConditionalFact(nameof(WebSocketsSupported))] - [ActiveIssue("https://github.com/dotnet/runtime/issues/42852", TestPlatforms.Browser)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/54153", TestPlatforms.Browser)] public async Task SendReceive_ConnectionClosedPrematurely_ReceiveAsyncFailsAndWebSocketStateUpdated() { var options = new LoopbackServer.Options { WebSocketEndpoint = true }; diff --git a/src/libraries/System.Net.WebSockets.Client/tests/System.Net.WebSockets.Client.Tests.csproj b/src/libraries/System.Net.WebSockets.Client/tests/System.Net.WebSockets.Client.Tests.csproj index 22b43cc0edcf9..956ee4d414612 100644 --- a/src/libraries/System.Net.WebSockets.Client/tests/System.Net.WebSockets.Client.Tests.csproj +++ b/src/libraries/System.Net.WebSockets.Client/tests/System.Net.WebSockets.Client.Tests.csproj @@ -9,12 +9,17 @@ WasmTestOnBrowser $(TestArchiveRoot)browseronly/ $(TestArchiveTestsRoot)$(OSPlatformConfig)/ + $(DefineConstants);TARGET_BROWSER + + + diff --git a/src/libraries/sendtohelixhelp.proj b/src/libraries/sendtohelixhelp.proj index 574bee9c7dce5..25d7168bdc463 100644 --- a/src/libraries/sendtohelixhelp.proj +++ b/src/libraries/sendtohelixhelp.proj @@ -277,6 +277,7 @@ $([MSBuild]::NormalizeDirectory('$(RepoRoot)', 'src', 'mono', 'wasm', 'emsdk')) $([MSBuild]::NormalizeDirectory('$(RepoRoot)', 'src', 'mono', 'wasm', 'build')) $([MSBuild]::NormalizeDirectory('$(ArtifactsDir)', 'bin', 'NetCoreServer', '$(NetCoreAppCurrent)-$(Configuration)')) + $([MSBuild]::NormalizeDirectory('$(ArtifactsDir)', 'bin', 'RemoteLoopServer', '$(NetCoreAppCurrent)-$(Configuration)')) @@ -311,6 +312,7 @@ +