From e3a1128fc78c2836c899bc5099d7e0261888f08f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 10 Sep 2020 16:12:48 -0700 Subject: [PATCH 1/5] Update comments to match official Win32 API documentation. (#42088) Co-authored-by: Aaron Robinson --- .../Common/src/Interop/Windows/SspiCli/Interop.SSPI.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libraries/Common/src/Interop/Windows/SspiCli/Interop.SSPI.cs b/src/libraries/Common/src/Interop/Windows/SspiCli/Interop.SSPI.cs index 93998b37ee7..04682754bc5 100644 --- a/src/libraries/Common/src/Interop/Windows/SspiCli/Interop.SSPI.cs +++ b/src/libraries/Common/src/Interop/Windows/SspiCli/Interop.SSPI.cs @@ -278,8 +278,8 @@ internal static partial class Interop public UNICODE_STRING* strCngAlgId; // CNG algorithm identifier. public int cChainingModes; // Set to 0 if CNG algorithm does not have a chaining mode. public UNICODE_STRING* rgstrChainingModes; // Set to NULL if CNG algorithm does not have a chaining mode. - public int dwMinBitLength; // Blacklist key sizes less than this. Set to 0 if not defined or CNG algorithm implies bit length. - public int dwMaxBitLength; // Blacklist key sizes greater than this. Set to 0 if not defined or CNG algorithm implies bit length. + public int dwMinBitLength; // Minimum bit length for the specified CNG algorithm. Set to 0 if not defined or CNG algorithm implies bit length. + public int dwMaxBitLength; // Maximum bit length for the specified CNG algorithm. Set to 0 if not defined or CNG algorithm implies bit length. public enum TlsAlgorithmUsage { From bb1257b05773193ede5609eae754a42f9afe0f74 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 10 Sep 2020 16:25:56 -0700 Subject: [PATCH 2/5] [release/5.0-rc2] Implement SocketsHttpHandler.ConnectCallback (#42075) * Implement SocketsHttpHandler.ConnectCallback --- .../System.Net.Http/ref/System.Net.Http.cs | 8 + .../src/Resources/Strings.resx | 3 + .../src/System.Net.Http.csproj | 3 +- .../BrowserHttpHandler/SocketsHttpHandler.cs | 7 + .../Http/SocketsHttpHandler/ConnectHelper.cs | 4 +- .../SocketsHttpHandler/HttpConnectionPool.cs | 28 +- .../HttpConnectionSettings.cs | 4 + .../SocketsConnectionFactory.cs | 106 -------- .../SocketsHttpConnectionContext.cs | 30 +++ .../SocketsHttpHandler/SocketsHttpHandler.cs | 14 + .../FunctionalTests/SocketsHttpHandlerTest.cs | 249 ++++++++++++++++++ 11 files changed, 344 insertions(+), 112 deletions(-) delete mode 100644 src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/SocketsConnectionFactory.cs create mode 100644 src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/SocketsHttpConnectionContext.cs diff --git a/src/libraries/System.Net.Http/ref/System.Net.Http.cs b/src/libraries/System.Net.Http/ref/System.Net.Http.cs index cc6c8995ac9..7469866690c 100644 --- a/src/libraries/System.Net.Http/ref/System.Net.Http.cs +++ b/src/libraries/System.Net.Http/ref/System.Net.Http.cs @@ -360,7 +360,15 @@ namespace System.Net.Http protected internal override System.Net.Http.HttpResponseMessage Send(System.Net.Http.HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) { throw null; } protected internal override System.Threading.Tasks.Task SendAsync(System.Net.Http.HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) { throw null; } public bool EnableMultipleHttp2Connections { get { throw null; } set { } } + public Func>? ConnectCallback { get { throw null; } set { } } } + public sealed class SocketsHttpConnectionContext + { + internal SocketsHttpConnectionContext() { } + public DnsEndPoint DnsEndPoint { get { throw null; } } + public HttpRequestMessage RequestMessage { get { throw null; } } + } + public enum HttpKeepAlivePingPolicy { WithActiveRequests, diff --git a/src/libraries/System.Net.Http/src/Resources/Strings.resx b/src/libraries/System.Net.Http/src/Resources/Strings.resx index 84bc59ad875..f3d2f81720b 100644 --- a/src/libraries/System.Net.Http/src/Resources/Strings.resx +++ b/src/libraries/System.Net.Http/src/Resources/Strings.resx @@ -585,4 +585,7 @@ Requesting HTTP version {0} with version policy {1} while server offers only version fallback. + + Synchronous operation is not supported when a ConnectCallback is specified on the SocketsHttpHandler instance. + diff --git a/src/libraries/System.Net.Http/src/System.Net.Http.csproj b/src/libraries/System.Net.Http/src/System.Net.Http.csproj index 1badaad9ca3..8b4fab540da 100644 --- a/src/libraries/System.Net.Http/src/System.Net.Http.csproj +++ b/src/libraries/System.Net.Http/src/System.Net.Http.csproj @@ -173,7 +173,7 @@ - + + diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/BrowserHttpHandler/SocketsHttpHandler.cs b/src/libraries/System.Net.Http/src/System/Net/Http/BrowserHttpHandler/SocketsHttpHandler.cs index 1d7ae3a0381..53224861b47 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/BrowserHttpHandler/SocketsHttpHandler.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/BrowserHttpHandler/SocketsHttpHandler.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; +using System.IO; using System.Net.Security; using System.Threading; using System.Threading.Tasks; @@ -170,5 +171,11 @@ namespace System.Net.Http get => throw new PlatformNotSupportedException(); set => throw new PlatformNotSupportedException(); } + + public Func>? ConnectCallback + { + get => throw new PlatformNotSupportedException(); + set => throw new PlatformNotSupportedException(); + } } } diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectHelper.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectHelper.cs index 931b8887fac..777b6e5c366 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectHelper.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectHelper.cs @@ -31,11 +31,11 @@ namespace System.Net.Http } } - public static async ValueTask ConnectAsync(SocketsConnectionFactory factory, DnsEndPoint endPoint, CancellationToken cancellationToken) + public static async ValueTask ConnectAsync(Func> callback, DnsEndPoint endPoint, HttpRequestMessage requestMessage, CancellationToken cancellationToken) { try { - return await factory.ConnectAsync(endPoint, cancellationToken).ConfigureAwait(false); + return await callback(new SocketsHttpConnectionContext(endPoint, requestMessage), cancellationToken).ConfigureAwait(false); } catch (OperationCanceledException ex) when (ex.CancellationToken == cancellationToken) { diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionPool.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionPool.cs index df4332c1d82..233b590e296 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionPool.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionPool.cs @@ -1286,20 +1286,42 @@ namespace System.Net.Http } } - private static readonly SocketsConnectionFactory s_defaultConnectionFactory = new SocketsConnectionFactory(SocketType.Stream, ProtocolType.Tcp); + private static async ValueTask DefaultConnectAsync(SocketsHttpConnectionContext context, CancellationToken cancellationToken) + { + Socket socket = new Socket(SocketType.Stream, ProtocolType.Tcp); + socket.NoDelay = true; + + try + { + await socket.ConnectAsync(context.DnsEndPoint, cancellationToken).ConfigureAwait(false); + return new NetworkStream(socket, ownsSocket: true); + } + catch + { + socket.Dispose(); + throw; + } + } + + private static readonly Func> s_defaultConnectCallback = DefaultConnectAsync; private ValueTask ConnectToTcpHostAsync(string host, int port, HttpRequestMessage initialRequest, bool async, CancellationToken cancellationToken) { if (async) { - SocketsConnectionFactory connectionFactory = s_defaultConnectionFactory; + Func> connectCallback = Settings._connectCallback ?? s_defaultConnectCallback; var endPoint = new DnsEndPoint(host, port); - return ConnectHelper.ConnectAsync(connectionFactory, endPoint, cancellationToken); + return ConnectHelper.ConnectAsync(connectCallback, endPoint, initialRequest, cancellationToken); } // Synchronous path. + if (Settings._connectCallback is not null) + { + throw new NotSupportedException(SR.net_http_sync_operations_not_allowed_with_connect_callback); + } + try { return new ValueTask(ConnectHelper.Connect(host, port, cancellationToken)); diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionSettings.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionSettings.cs index 177d8bc4884..00ce7157d86 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionSettings.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionSettings.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Net.Security; +using System.IO; using System.Threading; using System.Threading.Tasks; @@ -55,6 +56,8 @@ namespace System.Net.Http internal bool _enableMultipleHttp2Connections; + internal Func>? _connectCallback; + internal IDictionary? _properties; public HttpConnectionSettings() @@ -108,6 +111,7 @@ namespace System.Net.Http _requestHeaderEncodingSelector = _requestHeaderEncodingSelector, _responseHeaderEncodingSelector = _responseHeaderEncodingSelector, _enableMultipleHttp2Connections = _enableMultipleHttp2Connections, + _connectCallback = _connectCallback, }; } diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/SocketsConnectionFactory.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/SocketsConnectionFactory.cs deleted file mode 100644 index 98c8e899151..00000000000 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/SocketsConnectionFactory.cs +++ /dev/null @@ -1,106 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.IO; -using System.Net.Sockets; -using System.Threading; -using System.Threading.Tasks; - -namespace System.Net.Http -{ - /// - /// A factory to establish socket-based connections. - /// - /// - /// When constructed with , this factory will create connections with enabled. - /// In case of IPv6 sockets is also enabled. - /// - internal sealed class SocketsConnectionFactory - { - private readonly AddressFamily _addressFamily; - private readonly SocketType _socketType; - private readonly ProtocolType _protocolType; - - /// - /// Initializes a new instance of the class. - /// - /// The to forward to the socket. - /// The to forward to the socket. - /// The to forward to the socket. - public SocketsConnectionFactory( - AddressFamily addressFamily, - SocketType socketType, - ProtocolType protocolType) - { - _addressFamily = addressFamily; - _socketType = socketType; - _protocolType = protocolType; - } - - /// - /// Initializes a new instance of the class - /// that will forward to the Socket constructor. - /// - /// The to forward to the socket. - /// The to forward to the socket. - /// The created socket will be an IPv6 socket with enabled. - public SocketsConnectionFactory(SocketType socketType, ProtocolType protocolType) - : this(AddressFamily.InterNetworkV6, socketType, protocolType) - { - } - - public async ValueTask ConnectAsync( - EndPoint? endPoint, - CancellationToken cancellationToken = default) - { - if (endPoint == null) throw new ArgumentNullException(nameof(endPoint)); - cancellationToken.ThrowIfCancellationRequested(); - - Socket socket = CreateSocket(_addressFamily, _socketType, _protocolType, endPoint); - - try - { - await socket.ConnectAsync(endPoint, cancellationToken).ConfigureAwait(false); - return new NetworkStream(socket, true); - } - catch - { - socket.Dispose(); - throw; - } - } - - /// - /// Creates the socket that shall be used with the connection. - /// - /// The to forward to the socket. - /// The to forward to the socket. - /// The to forward to the socket. - /// The this socket will be connected to. - /// A new unconnected . - /// - /// In case of TCP sockets, the default implementation of this method will create a socket with enabled. - /// In case of IPv6 sockets is also be enabled. - /// - private Socket CreateSocket( - AddressFamily addressFamily, - SocketType socketType, - ProtocolType protocolType, - EndPoint? endPoint) - { - Socket socket = new Socket(addressFamily, socketType, protocolType); - - if (protocolType == ProtocolType.Tcp) - { - socket.NoDelay = true; - } - - if (addressFamily == AddressFamily.InterNetworkV6) - { - socket.DualMode = true; - } - - return socket; - } - } -} diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/SocketsHttpConnectionContext.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/SocketsHttpConnectionContext.cs new file mode 100644 index 00000000000..fbd38dfaef8 --- /dev/null +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/SocketsHttpConnectionContext.cs @@ -0,0 +1,30 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace System.Net.Http +{ + /// + /// Represents the context passed to the ConnectCallback for a SocketsHttpHandler instance. + /// + public sealed class SocketsHttpConnectionContext + { + private readonly DnsEndPoint _dnsEndPoint; + private readonly HttpRequestMessage _requestMessage; + + internal SocketsHttpConnectionContext(DnsEndPoint dnsEndPoint, HttpRequestMessage requestMessage) + { + _dnsEndPoint = dnsEndPoint; + _requestMessage = requestMessage; + } + + /// + /// The DnsEndPoint to be used by the ConnectCallback to establish the connection. + /// + public DnsEndPoint DnsEndPoint => _dnsEndPoint; + + /// + /// The initial HttpRequestMessage that is causing the connection to be created. + /// + public HttpRequestMessage RequestMessage => _requestMessage; + } +} diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/SocketsHttpHandler.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/SocketsHttpHandler.cs index 978e94a12d4..12b87278729 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/SocketsHttpHandler.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/SocketsHttpHandler.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Diagnostics; +using System.IO; using System.Net.Security; using System.Threading; using System.Threading.Tasks; @@ -362,6 +363,19 @@ namespace System.Net.Http internal bool SupportsProxy => true; internal bool SupportsRedirectConfiguration => true; + /// + /// When non-null, a custom callback used to open new connections. + /// + public Func>? ConnectCallback + { + get => _settings._connectCallback; + set + { + CheckDisposedOrStarted(); + _settings._connectCallback = value; + } + } + public IDictionary Properties => _settings._properties ?? (_settings._properties = new Dictionary()); diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/SocketsHttpHandlerTest.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/SocketsHttpHandlerTest.cs index 050700a84bb..a11c732ad0c 100644 --- a/src/libraries/System.Net.Http/tests/FunctionalTests/SocketsHttpHandlerTest.cs +++ b/src/libraries/System.Net.Http/tests/FunctionalTests/SocketsHttpHandlerTest.cs @@ -10,6 +10,7 @@ using System.Net.Security; using System.Net.Sockets; using System.Net.Test.Common; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using System.Security.Authentication; using System.Security.Cryptography.X509Certificates; using System.Text; @@ -1835,6 +1836,23 @@ namespace System.Net.Http.Functional.Tests } } + [Fact] + public void ConnectCallback_GetSet_Roundtrips() + { + using (var handler = new SocketsHttpHandler()) + { + Assert.Null(handler.ConnectCallback); + + Func> f = (context, token) => default; + + handler.ConnectCallback = f; + Assert.Equal(f, handler.ConnectCallback); + + handler.ConnectCallback = null; + Assert.Null(handler.ConnectCallback); + } + } + [Theory] [InlineData(false)] [InlineData(true)] @@ -1872,6 +1890,7 @@ namespace System.Net.Http.Functional.Tests Assert.NotNull(handler.SslOptions); Assert.True(handler.UseCookies); Assert.True(handler.UseProxy); + Assert.Null(handler.ConnectCallback); Assert.Throws(expectedExceptionType, () => handler.AllowAutoRedirect = false); Assert.Throws(expectedExceptionType, () => handler.AutomaticDecompression = DecompressionMethods.GZip); @@ -1891,6 +1910,7 @@ namespace System.Net.Http.Functional.Tests Assert.Throws(expectedExceptionType, () => handler.KeepAlivePingTimeout = TimeSpan.FromSeconds(5)); Assert.Throws(expectedExceptionType, () => handler.KeepAlivePingDelay = TimeSpan.FromSeconds(5)); Assert.Throws(expectedExceptionType, () => handler.KeepAlivePingPolicy = HttpKeepAlivePingPolicy.WithActiveRequests); + Assert.Throws(expectedExceptionType, () => handler.ConnectCallback = (context, token) => default); } } } @@ -2251,6 +2271,235 @@ namespace System.Net.Http.Functional.Tests } } + + public abstract class SocketsHttpHandlerTest_ConnectCallback : HttpClientHandlerTestBase + { + public SocketsHttpHandlerTest_ConnectCallback(ITestOutputHelper output) : base(output) { } + + [Fact] + public void ConnectCallback_SyncRequest_Fails() + { + using SocketsHttpHandler handler = new SocketsHttpHandler + { + ConnectCallback = (context, token) => default, + }; + + using HttpClient client = CreateHttpClient(handler); + + Assert.ThrowsAny(() => client.Send(new HttpRequestMessage(HttpMethod.Get, $"http://bing.com"))); + } + + [Fact] + public async void ConnectCallback_ContextHasCorrectProperties_Success() + { + await LoopbackServerFactory.CreateClientAndServerAsync( + async uri => + { + HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Get, uri); + + using HttpClientHandler handler = CreateHttpClientHandler(); + handler.ServerCertificateCustomValidationCallback = TestHelper.AllowAllCertificates; + var socketsHandler = (SocketsHttpHandler)GetUnderlyingSocketsHttpHandler(handler); + socketsHandler.ConnectCallback = async (context, token) => + { + Assert.Equal(uri.Host, context.DnsEndPoint.Host); + Assert.Equal(uri.Port, context.DnsEndPoint.Port); + Assert.Equal(requestMessage, context.RequestMessage); + + Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + await s.ConnectAsync(context.DnsEndPoint, token); + return new NetworkStream(s, ownsSocket: true); + }; + + using HttpClient client = CreateHttpClient(handler); + + HttpResponseMessage response = await client.SendAsync(requestMessage); + Assert.Equal("foo", await response.Content.ReadAsStringAsync()); + }, + async server => + { + await server.AcceptConnectionSendResponseAndCloseAsync(content: "foo"); + }); + } + + [Fact] + public async Task ConnectCallback_BindLocalAddress_Success() + { + await LoopbackServerFactory.CreateClientAndServerAsync( + async uri => + { + using HttpClientHandler handler = CreateHttpClientHandler(); + handler.ServerCertificateCustomValidationCallback = TestHelper.AllowAllCertificates; + var socketsHandler = (SocketsHttpHandler)GetUnderlyingSocketsHttpHandler(handler); + socketsHandler.ConnectCallback = async (context, token) => + { + Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + s.Bind(new IPEndPoint(IPAddress.Loopback, 0)); + await s.ConnectAsync(context.DnsEndPoint, token); + s.NoDelay = true; + return new NetworkStream(s, ownsSocket: true); + }; + + using HttpClient client = CreateHttpClient(handler); + + string response = await client.GetStringAsync(uri); + Assert.Equal("foo", response); + }, + async server => + { + await server.AcceptConnectionSendResponseAndCloseAsync(content: "foo"); + }); + } + + [Theory] + [InlineData(true)] + [InlineData(false)] + public async Task ConnectCallback_UseVirtualNetwork_Success(bool useSsl) + { + var vn = new VirtualNetwork(); + using var clientStream = new VirtualNetworkStream(vn, isServer: false, gracefulShutdown: true); + using var serverStream = new VirtualNetworkStream(vn, isServer: true, gracefulShutdown: true); + + GenericLoopbackOptions options = new GenericLoopbackOptions() { UseSsl = useSsl }; + + Task serverTask = Task.Run(async () => + { + using GenericLoopbackConnection loopbackConnection = await LoopbackServerFactory.CreateConnectionAsync(socket: null, serverStream, options); + await loopbackConnection.InitializeConnectionAsync(); + + HttpRequestData requestData = await loopbackConnection.ReadRequestDataAsync(); + await loopbackConnection.SendResponseAsync(content: "foo"); + + Assert.Equal("/foo", requestData.Path); + }); + + Task clientTask = Task.Run(async () => + { + using HttpClientHandler handler = CreateHttpClientHandler(); + handler.ServerCertificateCustomValidationCallback = TestHelper.AllowAllCertificates; + var socketsHandler = (SocketsHttpHandler)GetUnderlyingSocketsHttpHandler(handler); + socketsHandler.ConnectCallback = (context, token) => new ValueTask(clientStream); + + using HttpClient client = CreateHttpClient(handler); + + string response = await client.GetStringAsync($"{(options.UseSsl ? "https" : "http")}://nowhere.invalid/foo"); + Assert.Equal("foo", response); + }); + + await new[] { serverTask, clientTask }.WhenAllOrAnyFailed(60_000); + } + + [ConditionalTheory(nameof(PlatformSupportsUnixDomainSockets))] + [InlineData(true)] + [InlineData(false)] + public async Task ConnectCallback_UseUnixDomainSocket_Success(bool useSsl) + { + GenericLoopbackOptions options = new GenericLoopbackOptions() { UseSsl = useSsl }; + + string guid = $"{Guid.NewGuid():N}"; + UnixDomainSocketEndPoint serverEP = new UnixDomainSocketEndPoint(Path.Combine(Path.GetTempPath(), guid)); + Socket listenSocket = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.Unspecified); + listenSocket.Bind(serverEP); + listenSocket.Listen(); + + using HttpClientHandler handler = CreateHttpClientHandler(); + handler.ServerCertificateCustomValidationCallback = TestHelper.AllowAllCertificates; + var socketsHandler = (SocketsHttpHandler)GetUnderlyingSocketsHttpHandler(handler); + socketsHandler.ConnectCallback = async (context, token) => + { + string hostname = context.DnsEndPoint.Host; + UnixDomainSocketEndPoint clientEP = new UnixDomainSocketEndPoint(Path.Combine(Path.GetTempPath(), hostname)); + + Socket clientSocket = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.Unspecified); + await clientSocket.ConnectAsync(clientEP); + + return new NetworkStream(clientSocket, ownsSocket: true); + }; + + using HttpClient client = CreateHttpClient(handler); + + Task clientTask = client.GetStringAsync($"{(options.UseSsl ? "https" : "http")}://{guid}/foo"); + + Socket serverSocket = await listenSocket.AcceptAsync(); + using GenericLoopbackConnection loopbackConnection = await LoopbackServerFactory.CreateConnectionAsync(socket: null, new NetworkStream(serverSocket, ownsSocket: true), options); + await loopbackConnection.InitializeConnectionAsync(); + + HttpRequestData requestData = await loopbackConnection.ReadRequestDataAsync(); + Assert.Equal("/foo", requestData.Path); + + await loopbackConnection.SendResponseAsync(content: "foo"); + + string response = await clientTask; + Assert.Equal("foo", response); + } + + [Fact] + public async Task ConnectCallback_ConnectionPrefix_Success() + { + byte[] RequestPrefix = Encoding.UTF8.GetBytes("request prefix\r\n"); + byte[] ResponsePrefix = Encoding.UTF8.GetBytes("response prefix\r\n"); + + Socket listenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + listenSocket.Bind(new IPEndPoint(IPAddress.Loopback, 0)); + listenSocket.Listen(); + + using HttpClientHandler handler = CreateHttpClientHandler(); + var socketsHandler = (SocketsHttpHandler)GetUnderlyingSocketsHttpHandler(handler); + socketsHandler.ConnectCallback = async (context, token) => + { + Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + await clientSocket.ConnectAsync(listenSocket.LocalEndPoint); + + Stream clientStream = new NetworkStream(clientSocket, ownsSocket: true); + + await clientStream.WriteAsync(RequestPrefix); + + byte[] buffer = new byte[ResponsePrefix.Length]; + await clientStream.ReadAsync(buffer); + Assert.True(buffer.SequenceEqual(ResponsePrefix)); + + return clientStream; + }; + + using HttpClient client = CreateHttpClient(handler); + + Task clientTask = client.GetStringAsync($"http://nowhere.invalid/foo"); + + Socket serverSocket = await listenSocket.AcceptAsync(); + Stream serverStream = new NetworkStream(serverSocket, ownsSocket: true); + + byte[] buffer = new byte[RequestPrefix.Length]; + await serverStream.ReadAsync(buffer); + Assert.True(buffer.SequenceEqual(RequestPrefix)); + + await serverStream.WriteAsync(ResponsePrefix); + + using GenericLoopbackConnection loopbackConnection = await LoopbackServerFactory.CreateConnectionAsync(socket: null, serverStream); + await loopbackConnection.InitializeConnectionAsync(); + + HttpRequestData requestData = await loopbackConnection.ReadRequestDataAsync(); + Assert.Equal("/foo", requestData.Path); + + await loopbackConnection.SendResponseAsync(content: "foo"); + + string response = await clientTask; + Assert.Equal("foo", response); + } + + private static bool PlatformSupportsUnixDomainSockets => Socket.OSSupportsUnixDomainSockets; + } + + public sealed class SocketsHttpHandlerTest_ConnectCallback_Http11 : SocketsHttpHandlerTest_ConnectCallback + { + public SocketsHttpHandlerTest_ConnectCallback_Http11(ITestOutputHelper output) : base(output) { } + } + + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.SupportsAlpn))] + public sealed class SocketsHttpHandlerTest_ConnectCallback_Http2 : SocketsHttpHandlerTest_ConnectCallback + { + public SocketsHttpHandlerTest_ConnectCallback_Http2(ITestOutputHelper output) : base(output) { } + } + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.SupportsAlpn))] public sealed class SocketsHttpHandlerTest_Cookies_Http2 : HttpClientHandlerTest_Cookies { From 9e70a06cec175026cc5bca80c2be3176ae7d3591 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 10 Sep 2020 16:53:11 -0700 Subject: [PATCH 3/5] Temporarily disable arm64-intrin. UTF-16 validation (#42064) Co-authored-by: Levi Broderick --- .../src/System/Text/Unicode/Utf16Utility.Validation.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Text/Unicode/Utf16Utility.Validation.cs b/src/libraries/System.Private.CoreLib/src/System/Text/Unicode/Utf16Utility.Validation.cs index f2df0ccdf53..2600dff49a3 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Text/Unicode/Utf16Utility.Validation.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Text/Unicode/Utf16Utility.Validation.cs @@ -79,7 +79,11 @@ namespace System.Text.Unicode long tempUtf8CodeUnitCountAdjustment = 0; int tempScalarCountAdjustment = 0; - if ((AdvSimd.Arm64.IsSupported && BitConverter.IsLittleEndian) || Sse2.IsSupported) + // Per https://github.com/dotnet/runtime/issues/41699, temporarily disabling + // ARM64-intrinsicified code paths. ARM64 platforms may still use the vectorized + // non-intrinsicified 'else' block below. + + if (/* (AdvSimd.Arm64.IsSupported && BitConverter.IsLittleEndian) || */ Sse2.IsSupported) { if (inputLength >= Vector128.Count) { From 7d39776332446d8a84f5d542c80d264fa1cadbe7 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 11 Sep 2020 15:00:07 +0200 Subject: [PATCH 4/5] Remove machine state modifications on Unix (#42100) Changing /proc/sys/kernel/core_pattern is handled by core-eng and should not be done by helix consuming repositories. Also removing a workaround that has been fixed since (__CrashDumpFolder=/cores) on macOS. Also removing ulimit which is handled by core-eng as well. Co-authored-by: Viktor Hofer --- src/coreclr/tests/helixpublishwitharcade.proj | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/coreclr/tests/helixpublishwitharcade.proj b/src/coreclr/tests/helixpublishwitharcade.proj index cec547bd4ff..74a8c88a054 100644 --- a/src/coreclr/tests/helixpublishwitharcade.proj +++ b/src/coreclr/tests/helixpublishwitharcade.proj @@ -248,11 +248,8 @@ - - + - - From 0dbdb83b82b85bc3c21cf1b727832fb55af81933 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Fri, 11 Sep 2020 08:47:46 -0700 Subject: [PATCH 5/5] Update dependencies from https://github.com/dotnet/arcade build 20200909.8 (#42080) Microsoft.DotNet.Build.Tasks.Feed , Microsoft.DotNet.Build.Tasks.Packaging , Microsoft.DotNet.Build.Tasks.SharedFramework.Sdk , Microsoft.DotNet.Build.Tasks.TargetFramework.Sdk , Microsoft.DotNet.CodeAnalysis , Microsoft.DotNet.GenAPI , Microsoft.DotNet.GenFacades , Microsoft.DotNet.XUnitExtensions , Microsoft.DotNet.Arcade.Sdk , Microsoft.DotNet.Helix.Sdk , Microsoft.DotNet.RemoteExecutor , Microsoft.DotNet.VersionTools.Tasks , Microsoft.DotNet.XUnitConsoleRunner , Microsoft.DotNet.ApiCompat From Version 5.0.0-beta.20453.7 -> To Version 5.0.0-beta.20459.8 Co-authored-by: dotnet-maestro[bot] --- eng/Version.Details.xml | 56 ++++++++++++++++++++--------------------- eng/Versions.props | 20 +++++++-------- global.json | 8 +++--- 3 files changed, 42 insertions(+), 42 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 843b646448b..7b882429bb8 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -10,61 +10,61 @@ - + https://github.com/dotnet/arcade - 16b71a2f216c3c5be5860977c4cb03a95ee2f0e3 + 91470b0b14ba016c1fb78211b12775287c17b34e - + https://github.com/dotnet/arcade - 16b71a2f216c3c5be5860977c4cb03a95ee2f0e3 + 91470b0b14ba016c1fb78211b12775287c17b34e - + https://github.com/dotnet/arcade - 16b71a2f216c3c5be5860977c4cb03a95ee2f0e3 + 91470b0b14ba016c1fb78211b12775287c17b34e - + https://github.com/dotnet/arcade - 16b71a2f216c3c5be5860977c4cb03a95ee2f0e3 + 91470b0b14ba016c1fb78211b12775287c17b34e - + https://github.com/dotnet/arcade - 16b71a2f216c3c5be5860977c4cb03a95ee2f0e3 + 91470b0b14ba016c1fb78211b12775287c17b34e - + https://github.com/dotnet/arcade - 16b71a2f216c3c5be5860977c4cb03a95ee2f0e3 + 91470b0b14ba016c1fb78211b12775287c17b34e - + https://github.com/dotnet/arcade - 16b71a2f216c3c5be5860977c4cb03a95ee2f0e3 + 91470b0b14ba016c1fb78211b12775287c17b34e - + https://github.com/dotnet/arcade - 16b71a2f216c3c5be5860977c4cb03a95ee2f0e3 + 91470b0b14ba016c1fb78211b12775287c17b34e - + https://github.com/dotnet/arcade - 16b71a2f216c3c5be5860977c4cb03a95ee2f0e3 + 91470b0b14ba016c1fb78211b12775287c17b34e - + https://github.com/dotnet/arcade - 16b71a2f216c3c5be5860977c4cb03a95ee2f0e3 + 91470b0b14ba016c1fb78211b12775287c17b34e - + https://github.com/dotnet/arcade - 16b71a2f216c3c5be5860977c4cb03a95ee2f0e3 + 91470b0b14ba016c1fb78211b12775287c17b34e - + https://github.com/dotnet/arcade - 16b71a2f216c3c5be5860977c4cb03a95ee2f0e3 + 91470b0b14ba016c1fb78211b12775287c17b34e - + https://github.com/dotnet/arcade - 16b71a2f216c3c5be5860977c4cb03a95ee2f0e3 + 91470b0b14ba016c1fb78211b12775287c17b34e - + https://github.com/dotnet/arcade - 16b71a2f216c3c5be5860977c4cb03a95ee2f0e3 + 91470b0b14ba016c1fb78211b12775287c17b34e https://dev.azure.com/dnceng/internal/_git/dotnet-optimization diff --git a/eng/Versions.props b/eng/Versions.props index 1b725be8086..9e90b2ae727 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -51,16 +51,16 @@ 3.8.0-2.20403.2 - 5.0.0-beta.20453.7 - 5.0.0-beta.20453.7 - 5.0.0-beta.20453.7 - 5.0.0-beta.20453.7 - 5.0.0-beta.20453.7 - 5.0.0-beta.20453.7 - 2.5.1-beta.20453.7 - 5.0.0-beta.20453.7 - 5.0.0-beta.20453.7 - 5.0.0-beta.20453.7 + 5.0.0-beta.20459.8 + 5.0.0-beta.20459.8 + 5.0.0-beta.20459.8 + 5.0.0-beta.20459.8 + 5.0.0-beta.20459.8 + 5.0.0-beta.20459.8 + 2.5.1-beta.20459.8 + 5.0.0-beta.20459.8 + 5.0.0-beta.20459.8 + 5.0.0-beta.20459.8 5.0.0-preview.4.20202.18 5.0.0-preview.4.20202.18 diff --git a/global.json b/global.json index b5da99f6166..156b9cc93e5 100644 --- a/global.json +++ b/global.json @@ -12,10 +12,10 @@ "python3": "3.7.1" }, "msbuild-sdks": { - "Microsoft.DotNet.Build.Tasks.TargetFramework.Sdk": "5.0.0-beta.20453.7", - "Microsoft.DotNet.Arcade.Sdk": "5.0.0-beta.20453.7", - "Microsoft.DotNet.Build.Tasks.SharedFramework.Sdk": "5.0.0-beta.20453.7", - "Microsoft.DotNet.Helix.Sdk": "5.0.0-beta.20453.7", + "Microsoft.DotNet.Build.Tasks.TargetFramework.Sdk": "5.0.0-beta.20459.8", + "Microsoft.DotNet.Arcade.Sdk": "5.0.0-beta.20459.8", + "Microsoft.DotNet.Build.Tasks.SharedFramework.Sdk": "5.0.0-beta.20459.8", + "Microsoft.DotNet.Helix.Sdk": "5.0.0-beta.20459.8", "Microsoft.FIX-85B6-MERGE-9C38-CONFLICT": "1.0.0", "Microsoft.NET.Sdk.IL": "5.0.0-preview.8.20359.4", "Microsoft.Build.NoTargets": "1.0.53",