private async ValueTask <HttpConnection> CreateConnection(HttpRequestMessage request, HttpConnectionKey key, HttpConnectionPool pool)
        {
            Uri uri = request.RequestUri;

            Stream stream = await ConnectHelper.ConnectAsync(uri.IdnHost, uri.Port).ConfigureAwait(false);

            TransportContext transportContext = null;

            if (uri.Scheme == UriScheme.Https)
            {
                SslStream sslStream = await EstablishSslConnection(uri.IdnHost, request, stream).ConfigureAwait(false);

                stream           = sslStream;
                transportContext = sslStream.TransportContext;
            }

            if (pool == null)
            {
                pool = _connectionPoolTable.GetOrAdd(key, _ => new HttpConnectionPool());
            }

            var connection = new HttpConnection(pool, key, uri.IdnHost, stream, transportContext, false);

            return(connection);
        }
Beispiel #2
0
        private async ValueTask <HttpConnection> CreateConnectionAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            // If a non-infinite connect timeout has been set, create and use a new CancellationToken that'll be canceled
            // when either the original token is canceled or a connect timeout occurs.
            CancellationTokenSource cancellationWithConnectTimeout = null;

            if (Settings._connectTimeout != Timeout.InfiniteTimeSpan)
            {
                cancellationWithConnectTimeout = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, default);
                cancellationWithConnectTimeout.CancelAfter(Settings._connectTimeout);
                cancellationToken = cancellationWithConnectTimeout.Token;
            }

            try
            {
                Stream stream = await
                                    (_proxyUri == null ?
                                    ConnectHelper.ConnectAsync(_host, _port, cancellationToken) :
                                    (_sslOptions == null ?
                                     ConnectHelper.ConnectAsync(_proxyUri.IdnHost, _proxyUri.Port, cancellationToken) :
                                     EstablishProxyTunnel(cancellationToken))).ConfigureAwait(false);

                TransportContext transportContext = null;
                if (_sslOptions != null)
                {
                    // TODO #25206 and #24430: Register/IsCancellationRequested should be removable once SslStream auth and sockets respect cancellation.
                    CancellationTokenRegistration ctr = cancellationToken.Register(s => ((Stream)s).Dispose(), stream);
                    try
                    {
                        SslStream sslStream = await ConnectHelper.EstablishSslConnectionAsync(_sslOptions, request, stream, cancellationToken).ConfigureAwait(false);

                        stream           = sslStream;
                        transportContext = sslStream.TransportContext;
                        cancellationToken.ThrowIfCancellationRequested(); // to handle race condition where stream is dispose of by cancellation after auth
                    }
                    catch (Exception exc)
                    {
                        stream.Dispose(); // in case cancellation occurs after successful SSL auth
                        if (HttpConnection.ShouldWrapInOperationCanceledException(exc, cancellationToken))
                        {
                            throw HttpConnection.CreateOperationCanceledException(exc, cancellationToken);
                        }
                        throw;
                    }
                    finally
                    {
                        ctr.Dispose();
                    }
                }

                return(_maxConnections == int.MaxValue ?
                       new HttpConnection(this, stream, transportContext) :
                       new HttpConnectionWithFinalizer(this, stream, transportContext)); // finalizer needed to signal the pool when a connection is dropped
            }
            finally
            {
                cancellationWithConnectTimeout?.Dispose();
            }
        }
Beispiel #3
0
        private ValueTask <HttpConnection> GetOrCreateConnection(HttpRequestMessage request, Uri proxyUri, CancellationToken cancellationToken)
        {
            var key = new HttpConnectionKey(proxyUri);
            HttpConnectionPool pool = _connectionPools.GetOrAddPool(key);

            return(pool.GetConnectionAsync(async(state, ct) =>
            {
                Stream stream = await ConnectHelper.ConnectAsync(state.proxyUri.IdnHost, state.proxyUri.Port, ct).ConfigureAwait(false);
                return new HttpConnection(state.pool, state.key, null, stream, null, true);
            }, (pool: pool, key: key, request: request, proxyUri: proxyUri), cancellationToken));
        }
Beispiel #4
0
        private async ValueTask <HttpConnection> CreateConnection(
            HttpRequestMessage request, HttpConnectionKey key, HttpConnectionPool pool, CancellationToken cancellationToken)
        {
            Uri uri = request.RequestUri;

            Stream stream = await ConnectHelper.ConnectAsync(uri.IdnHost, uri.Port, cancellationToken).ConfigureAwait(false);

            TransportContext transportContext = null;

            if (uri.Scheme == UriScheme.Https)
            {
                // Get the appropriate host name to use for the SSL connection, allowing a host header to override.
                string host = request.Headers.Host;
                if (host == null)
                {
                    // No host header, use the host from the Uri.
                    host = uri.IdnHost;
                }
                else
                {
                    // There is a host header.  Use it, but first see if we need to trim off a port.
                    int colonPos = host.IndexOf(':');
                    if (colonPos >= 0)
                    {
                        // There is colon, which could either be a port separator or a separator in
                        // an IPv6 address.  See if this is an IPv6 address; if it's not, use everything
                        // before the colon as the host name, and if it is, use everything before the last
                        // colon iff the last colon is after the end of the IPv6 address (otherwise it's a
                        // part of the address).
                        int ipV6AddressEnd = host.IndexOf(']');
                        if (ipV6AddressEnd == -1)
                        {
                            host = host.Substring(0, colonPos);
                        }
                        else
                        {
                            colonPos = host.LastIndexOf(':');
                            if (colonPos > ipV6AddressEnd)
                            {
                                host = host.Substring(0, colonPos);
                            }
                        }
                    }
                }

                // Establish the connection using the parsed host name.
                SslStream sslStream = await EstablishSslConnection(host, request, stream, cancellationToken).ConfigureAwait(false);

                stream           = sslStream;
                transportContext = sslStream.TransportContext;
            }

            return(new HttpConnection(pool, key, uri.IdnHost, stream, transportContext, false));
        }
Beispiel #5
0
        private async ValueTask <HttpConnection> CreateConnectionAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            Stream stream = await ConnectHelper.ConnectAsync(_key, cancellationToken).ConfigureAwait(false);

            TransportContext transportContext = null;

            if (_key.IsSecure)
            {
                SslStream sslStream = await ConnectHelper.EstablishSslConnectionAsync(_pools.Settings, _key.SslHostName, request, stream, cancellationToken).ConfigureAwait(false);

                stream           = sslStream;
                transportContext = sslStream.TransportContext;
            }

            return(new HttpConnection(this, stream, transportContext));
        }
Beispiel #6
0
        private async ValueTask <HttpConnection> CreateConnectionAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            Stream stream = await ConnectHelper.ConnectAsync(_key, cancellationToken).ConfigureAwait(false);

            TransportContext transportContext = null;

            if (_key.IsSecure)
            {
                SslStream sslStream = await ConnectHelper.EstablishSslConnectionAsync(_sslOptions, request, stream, cancellationToken).ConfigureAwait(false);

                stream           = sslStream;
                transportContext = sslStream.TransportContext;
            }

            return(_maxConnections == int.MaxValue ?
                   new HttpConnection(this, stream, transportContext) :
                   new HttpConnectionWithFinalizer(this, stream, transportContext)); // finalizer needed to signal the pool when a connection is dropped
        }
Beispiel #7
0
        private async ValueTask <HttpConnection> CreateConnection(HttpRequestMessage request, HttpConnectionKey key, HttpConnectionPool pool)
        {
            Uri uri = request.RequestUri;

            Stream stream = await ConnectHelper.ConnectAsync(uri.IdnHost, uri.Port).ConfigureAwait(false);

            TransportContext transportContext = null;

            if (HttpUtilities.IsSupportedSecureScheme(uri.Scheme))
            {
                SslStream sslStream = await EstablishSslConnection(uri.IdnHost, request, stream).ConfigureAwait(false);

                stream           = sslStream;
                transportContext = sslStream.TransportContext;
            }

            return(new HttpConnection(pool, key, uri.IdnHost, stream, transportContext, false));
        }
        private async ValueTask <HttpConnection> CreateConnectionAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            // If a non-infinite connect timeout has been set, create and use a new CancellationToken that'll be canceled
            // when either the original token is canceled or a connect timeout occurs.
            CancellationTokenSource cancellationWithConnectTimeout = null;

            if (Settings._connectTimeout != Timeout.InfiniteTimeSpan)
            {
                cancellationWithConnectTimeout = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, default);
                cancellationWithConnectTimeout.CancelAfter(Settings._connectTimeout);
                cancellationToken = cancellationWithConnectTimeout.Token;
            }

            try
            {
                Stream stream = await
                                    (_proxyUri == null ?
                                    ConnectHelper.ConnectAsync(_host, _port, cancellationToken) :
                                    (_sslOptions == null ?
                                     ConnectHelper.ConnectAsync(_proxyUri.IdnHost, _proxyUri.Port, cancellationToken) :
                                     EstablishProxyTunnel(cancellationToken))).ConfigureAwait(false);

                TransportContext transportContext = null;
                if (_sslOptions != null)
                {
                    SslStream sslStream = await ConnectHelper.EstablishSslConnectionAsync(_sslOptions, request, stream, cancellationToken).ConfigureAwait(false);

                    stream           = sslStream;
                    transportContext = sslStream.TransportContext;
                }

                return(_maxConnections == int.MaxValue ?
                       new HttpConnection(this, stream, transportContext) :
                       new HttpConnectionWithFinalizer(this, stream, transportContext)); // finalizer needed to signal the pool when a connection is dropped
            }
            finally
            {
                cancellationWithConnectTimeout?.Dispose();
            }
        }
        private async ValueTask <HttpConnection> GetOrCreateConnection(HttpRequestMessage request, Uri proxyUri)
        {
            HttpConnectionKey key = new HttpConnectionKey(proxyUri);

            HttpConnectionPool pool;

            if (_connectionPoolTable.TryGetValue(key, out pool))
            {
                HttpConnection poolConnection = pool.GetConnection();
                if (poolConnection != null)
                {
                    return(poolConnection);
                }
            }

            Stream stream = await ConnectHelper.ConnectAsync(proxyUri.Host, proxyUri.Port).ConfigureAwait(false);

            if (pool == null)
            {
                pool = _connectionPoolTable.GetOrAdd(key, _ => new HttpConnectionPool());
            }

            return(new HttpConnection(pool, key, stream, null, true));
        }
Beispiel #10
0
        private async ValueTask <(HttpConnection, HttpResponseMessage)> CreateConnectionAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            // If a non-infinite connect timeout has been set, create and use a new CancellationToken that'll be canceled
            // when either the original token is canceled or a connect timeout occurs.
            CancellationTokenSource cancellationWithConnectTimeout = null;

            if (Settings._connectTimeout != Timeout.InfiniteTimeSpan)
            {
                cancellationWithConnectTimeout = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, default);
                cancellationWithConnectTimeout.CancelAfter(Settings._connectTimeout);
                cancellationToken = cancellationWithConnectTimeout.Token;
            }

            try
            {
                Socket socket = null;
                Stream stream = null;
                switch (_kind)
                {
                case HttpConnectionKind.Http:
                case HttpConnectionKind.Https:
                case HttpConnectionKind.ProxyConnect:
                    (socket, stream) = await ConnectHelper.ConnectAsync(_host, _port, cancellationToken).ConfigureAwait(false);

                    break;

                case HttpConnectionKind.Proxy:
                    (socket, stream) = await ConnectHelper.ConnectAsync(_proxyUri.IdnHost, _proxyUri.Port, cancellationToken).ConfigureAwait(false);

                    break;

                case HttpConnectionKind.ProxyTunnel:
                case HttpConnectionKind.SslProxyTunnel:
                    HttpResponseMessage response;
                    (stream, response) = await EstablishProxyTunnel(cancellationToken).ConfigureAwait(false);

                    if (response != null)
                    {
                        // Return non-success response from proxy.
                        response.RequestMessage = request;
                        return(null, response);
                    }
                    break;
                }

                TransportContext transportContext = null;
                if (_sslOptions != null)
                {
                    SslStream sslStream = await ConnectHelper.EstablishSslConnectionAsync(_sslOptions, request, stream, cancellationToken).ConfigureAwait(false);

                    stream           = sslStream;
                    transportContext = sslStream.TransportContext;
                }

                HttpConnection connection = _maxConnections == int.MaxValue ?
                                            new HttpConnection(this, socket, stream, transportContext) :
                                            new HttpConnectionWithFinalizer(this, socket, stream, transportContext); // finalizer needed to signal the pool when a connection is dropped
                return(connection, null);
            }
            finally
            {
                cancellationWithConnectTimeout?.Dispose();
            }
        }