<commit_before>﻿// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System.Collections.Concurrent;
using System.Diagnostics;
using System.IO;
using System.Net.Security;
using System.Net.Sockets;
using System.Runtime.CompilerServices;
using System.Security.Cryptography.X509Certificates;
using System.Threading;
using System.Threading.Tasks;

namespace System.Net.Http
{
    internal static class ConnectHelper
    {
        /// <summary>Pool of event args to use to establish connections.</summary>
        private static readonly ConcurrentQueue<ConnectEventArgs>.Segment s_connectEventArgs =
            new ConcurrentQueue<ConnectEventArgs>.Segment(
                ConcurrentQueue<ConnectEventArgs>.Segment.RoundUpToPowerOf2(Math.Max(2, Environment.ProcessorCount)));

        /// <summary>
        /// Helper type used by HttpClientHandler when wrapping SocketsHttpHandler to map its
        /// certificate validation callback to the one used by SslStream.
        /// </summary>
        internal sealed class CertificateCallbackMapper
        {
            public readonly Func<HttpRequestMessage, X509Certificate2, X509Chain, SslPolicyErrors, bool> FromHttpClientHandler;
            public readonly RemoteCertificateValidationCallback ForSocketsHttpHandler;

            public CertificateCallbackMapper(Func<HttpRequestMessage, X509Certificate2, X509Chain, SslPolicyErrors, bool> fromHttpClientHandler)
            {
                FromHttpClientHandler = fromHttpClientHandler;
                ForSocketsHttpHandler = (object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) =>
                    FromHttpClientHandler(sender as HttpRequestMessage, certificate as X509Certificate2, chain, sslPolicyErrors);
            }
        }

        public static async ValueTask<(Socket, Stream)> ConnectAsync(string host, int port, CancellationToken cancellationToken)
        {
            // Rather than creating a new Socket and calling ConnectAsync on it, we use the static
            // Socket.ConnectAsync with a SocketAsyncEventArgs, as we can then use Socket.CancelConnectAsync
            // to cancel it if needed. Rent or allocate one.
            ConnectEventArgs saea;
            if (!s_connectEventArgs.TryDequeue(out saea))
            {
                saea = new ConnectEventArgs();
            }

            try
            {
                saea.Initialize(cancellationToken);

                // Configure which server to which to connect.
                saea.RemoteEndPoint = IPAddress.TryParse(host, out IPAddress address) ?
                    (EndPoint)new IPEndPoint(address, port) :
                    new DnsEndPoint(host, port);

                // Initiate the connection.
                if (Socket.ConnectAsync(SocketType.Stream, ProtocolType.Tcp, saea))
                {
                    // Connect completing asynchronously. Enable it to be canceled and wait for it.
                    using (cancellationToken.Register(s => Socket.CancelConnectAsync((SocketAsyncEventArgs)s), saea))
                    {
                        await saea.Builder.Task.ConfigureAwait(false);
                    }
                }
                else if (saea.SocketError != SocketError.Success)
                {
                    // Connect completed synchronously but unsuccessfully.
                    throw new SocketException((int)saea.SocketError);
                }

                Debug.Assert(saea.SocketError == SocketError.Success, $"Expected Success, got {saea.SocketError}.");
                Debug.Assert(saea.ConnectSocket != null, "Expected non-null socket");

                // Configure the socket and return a stream for it.
                Socket socket = saea.ConnectSocket;<commit_msg>Always use DnsEndPoint in SocketHttpHandler's ConnectAsync (#29286)<commit_after>﻿// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System.Collections.Concurrent;
using System.Diagnostics;
using System.IO;
using System.Net.Security;
using System.Net.Sockets;
using System.Runtime.CompilerServices;
using System.Security.Cryptography.X509Certificates;
using System.Threading;
using System.Threading.Tasks;

namespace System.Net.Http
{
    internal static class ConnectHelper
    {
        /// <summary>Pool of event args to use to establish connections.</summary>
        private static readonly ConcurrentQueue<ConnectEventArgs>.Segment s_connectEventArgs =
            new ConcurrentQueue<ConnectEventArgs>.Segment(
                ConcurrentQueue<ConnectEventArgs>.Segment.RoundUpToPowerOf2(Math.Max(2, Environment.ProcessorCount)));

        /// <summary>
        /// Helper type used by HttpClientHandler when wrapping SocketsHttpHandler to map its
        /// certificate validation callback to the one used by SslStream.
        /// </summary>
        internal sealed class CertificateCallbackMapper
        {
            public readonly Func<HttpRequestMessage, X509Certificate2, X509Chain, SslPolicyErrors, bool> FromHttpClientHandler;
            public readonly RemoteCertificateValidationCallback ForSocketsHttpHandler;

            public CertificateCallbackMapper(Func<HttpRequestMessage, X509Certificate2, X509Chain, SslPolicyErrors, bool> fromHttpClientHandler)
            {
                FromHttpClientHandler = fromHttpClientHandler;
                ForSocketsHttpHandler = (object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) =>
                    FromHttpClientHandler(sender as HttpRequestMessage, certificate as X509Certificate2, chain, sslPolicyErrors);
            }
        }

        public static async ValueTask<(Socket, Stream)> ConnectAsync(string host, int port, CancellationToken cancellationToken)
        {
            // Rather than creating a new Socket and calling ConnectAsync on it, we use the static
            // Socket.ConnectAsync with a SocketAsyncEventArgs, as we can then use Socket.CancelConnectAsync
            // to cancel it if needed. Rent or allocate one.
            ConnectEventArgs saea;
            if (!s_connectEventArgs.TryDequeue(out saea))
            {
                saea = new ConnectEventArgs();
            }

            try
            {
                saea.Initialize(cancellationToken);

                // Configure which server to which to connect.
                saea.RemoteEndPoint = new DnsEndPoint(host, port);

                // Initiate the connection.
                if (Socket.ConnectAsync(SocketType.Stream, ProtocolType.Tcp, saea))
                {
                    // Connect completing asynchronously. Enable it to be canceled and wait for it.
                    using (cancellationToken.Register(s => Socket.CancelConnectAsync((SocketAsyncEventArgs)s), saea))
                    {
                        await saea.Builder.Task.ConfigureAwait(false);
                    }
                }
                else if (saea.SocketError != SocketError.Success)
                {
                    // Connect completed synchronously but unsuccessfully.
                    throw new SocketException((int)saea.SocketError);
                }

                Debug.Assert(saea.SocketError == SocketError.Success, $"Expected Success, got {saea.SocketError}.");
                Debug.Assert(saea.ConnectSocket != null, "Expected non-null socket");

                // Configure the socket and return a stream for it.
                Socket socket = saea.ConnectSocket;
{'fraction_non_alphanumeric': 0.07029449423815622, 'fraction_numerical': 0.008066581306017926, 'mean_word_length': 2.319592010199745, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 27, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6989876', 'n_tokens_mistral': 1887, 'n_tokens_neox': 1776, 'n_words': 544}