/// <summary>Initializes the pools.</summary> public HttpConnectionPoolManager(HttpConnectionSettings settings) { _settings = settings; _maxConnectionsPerServer = settings._maxConnectionsPerServer; _avoidStoringConnections = settings._pooledConnectionIdleTimeout == TimeSpan.Zero || settings._pooledConnectionLifetime == TimeSpan.Zero; _pools = new ConcurrentDictionary <HttpConnectionKey, HttpConnectionPool>(); // Start out with the timer not running, since we have no pools. // When it does run, run it with a frequency based on the idle timeout. if (!_avoidStoringConnections) { if (settings._pooledConnectionIdleTimeout == Timeout.InfiniteTimeSpan) { const int DefaultScavengeSeconds = 30; _cleanPoolTimeout = TimeSpan.FromSeconds(DefaultScavengeSeconds); } else { const int ScavengesPerIdle = 4; const int MinScavengeSeconds = 1; TimeSpan timerPeriod = settings._pooledConnectionIdleTimeout / ScavengesPerIdle; _cleanPoolTimeout = timerPeriod.TotalSeconds >= MinScavengeSeconds ? timerPeriod : TimeSpan.FromSeconds(MinScavengeSeconds); } bool restoreFlow = false; try { // Don't capture the current ExecutionContext and its AsyncLocals onto the timer causing them to live forever if (!ExecutionContext.IsFlowSuppressed()) { ExecutionContext.SuppressFlow(); restoreFlow = true; } _cleaningTimer = new Timer(s => ((HttpConnectionPoolManager)s).RemoveStalePools(), this, Timeout.Infinite, Timeout.Infinite); } finally { // Restore the current ExecutionContext if (restoreFlow) { ExecutionContext.RestoreFlow(); } } } // Figure out proxy stuff. if (settings._useProxy) { _proxy = settings._proxy ?? SystemProxyInfo.ConstructSystemProxy(); if (_proxy != null) { _proxyCredentials = _proxy.Credentials ?? settings._defaultProxyCredentials; } } }
public HttpProxyConnectionHandler(HttpConnectionSettings settings, HttpMessageHandler innerHandler) { Debug.Assert(innerHandler != null); _innerHandler = innerHandler; _proxy = (settings._useProxy && settings._proxy != null) ? settings._proxy : new PassthroughWebProxy(s_proxyFromEnvironment.Value); _defaultCredentials = settings._defaultProxyCredentials; _connectionPools = new HttpConnectionPools(settings._maxConnectionsPerServer); }
public HttpProxyConnectionHandler(HttpConnectionSettings settings, HttpMessageHandler innerHandler) { Debug.Assert(innerHandler != null); Debug.Assert(settings._useProxy); _innerHandler = innerHandler; _proxy = settings._proxy ?? ConstructSystemProxy(); _defaultCredentials = settings._defaultProxyCredentials; _connectionPools = new HttpConnectionPools(settings, settings._maxConnectionsPerServer, usingProxy: true); }
/// <summary>Creates a copy of the settings but with some values normalized to suit the implementation.</summary> public HttpConnectionSettings CloneAndNormalize() { // Force creation of the cookie container if needed, so the original and clone share the same instance. if (_useCookies && _cookieContainer == null) { _cookieContainer = new CookieContainer(); } var settings = new HttpConnectionSettings() { _allowAutoRedirect = _allowAutoRedirect, _automaticDecompression = _automaticDecompression, _cookieContainer = _cookieContainer, _connectTimeout = _connectTimeout, _credentials = _credentials, _defaultProxyCredentials = _defaultProxyCredentials, _defaultCredentialsUsedForProxy = _defaultCredentialsUsedForProxy, _defaultCredentialsUsedForServer = _defaultCredentialsUsedForServer, _expect100ContinueTimeout = _expect100ContinueTimeout, _maxAutomaticRedirections = _maxAutomaticRedirections, _maxConnectionsPerServer = _maxConnectionsPerServer, _maxHttpVersion = _maxHttpVersion, _maxResponseDrainSize = _maxResponseDrainSize, _maxResponseDrainTime = _maxResponseDrainTime, _maxResponseHeadersLength = _maxResponseHeadersLength, _pooledConnectionLifetime = _pooledConnectionLifetime, _pooledConnectionIdleTimeout = _pooledConnectionIdleTimeout, _preAuthenticate = _preAuthenticate, _properties = _properties, _proxy = _proxy, _sslOptions = _sslOptions?.ShallowClone(), // shallow clone the options for basic prevention of mutation issues while processing _useCookies = _useCookies, _useProxy = _useProxy, _keepAlivePingTimeout = _keepAlivePingTimeout, _keepAlivePingDelay = _keepAlivePingDelay, _keepAlivePingPolicy = _keepAlivePingPolicy, _requestHeaderEncodingSelector = _requestHeaderEncodingSelector, _responseHeaderEncodingSelector = _responseHeaderEncodingSelector, _enableMultipleHttp2Connections = _enableMultipleHttp2Connections, _connectCallback = _connectCallback, _plaintextStreamFilter = _plaintextStreamFilter, _initialHttp2StreamWindowSize = _initialHttp2StreamWindowSize, _activityHeadersPropagator = _activityHeadersPropagator, }; // TODO: Remove if/when QuicImplementationProvider is removed from System.Net.Quic. if (HttpConnectionPool.IsHttp3Supported()) { settings._quicImplementationProvider = _quicImplementationProvider; } return(settings); }
/// <summary>Creates a copy of the settings but with some values normalized to suit the implementation.</summary> public HttpConnectionSettings CloneAndNormalize() { // Force creation of the cookie container if needed, so the original and clone share the same instance. if (_useCookies && _cookieContainer == null) { _cookieContainer = new CookieContainer(); } var settings = new HttpConnectionSettings() { _allowAutoRedirect = _allowAutoRedirect, _automaticDecompression = _automaticDecompression, _cookieContainer = _cookieContainer, _connectTimeout = _connectTimeout, _credentials = _credentials, _defaultProxyCredentials = _defaultProxyCredentials, _defaultCredentialsUsedForProxy = _defaultCredentialsUsedForProxy, _defaultCredentialsUsedForServer = _defaultCredentialsUsedForServer, _expect100ContinueTimeout = _expect100ContinueTimeout, _maxAutomaticRedirections = _maxAutomaticRedirections, _maxConnectionsPerServer = _maxConnectionsPerServer, _maxHttpVersion = _maxHttpVersion, _maxResponseDrainSize = _maxResponseDrainSize, _maxResponseDrainTime = _maxResponseDrainTime, _maxResponseHeadersLength = _maxResponseHeadersLength, _pooledConnectionLifetime = _pooledConnectionLifetime, _pooledConnectionIdleTimeout = _pooledConnectionIdleTimeout, _preAuthenticate = _preAuthenticate, _properties = _properties, _proxy = _proxy, _sslOptions = _sslOptions?.ShallowClone(), // shallow clone the options for basic prevention of mutation issues while processing _useCookies = _useCookies, _useProxy = _useProxy, _keepAlivePingTimeout = _keepAlivePingTimeout, _keepAlivePingDelay = _keepAlivePingDelay, _keepAlivePingPolicy = _keepAlivePingPolicy, _requestHeaderEncodingSelector = _requestHeaderEncodingSelector, _responseHeaderEncodingSelector = _responseHeaderEncodingSelector, _enableMultipleHttp2Connections = _enableMultipleHttp2Connections, _connectCallback = _connectCallback, _plaintextStreamFilter = _plaintextStreamFilter }; // TODO: Replace with Platform-Guard Assertion Annotations once https://github.com/dotnet/runtime/issues/44922 is finished // TODO: Remove if/when QuicImplementationProvider is removed from System.Net.Quic. if ((OperatingSystem.IsLinux() && !OperatingSystem.IsAndroid()) || OperatingSystem.IsWindows() || OperatingSystem.IsMacOS()) { settings._quicImplementationProvider = _quicImplementationProvider; } return(settings); }
public Http2StreamWindowManager(Http2Connection connection, Http2Stream stream) { HttpConnectionSettings settings = connection._pool.Settings; _streamWindowSize = settings._initialHttp2StreamWindowSize; _deliveredBytes = 0; _lastWindowUpdate = default; if (NetEventSource.Log.IsEnabled()) { stream.Trace($"[FlowControl] InitialClientStreamWindowSize: {StreamWindowSize}, StreamWindowThreshold: {StreamWindowThreshold}, WindowScaleThresholdMultiplier: {WindowScaleThresholdMultiplier}"); } }
/// <summary>Initializes the pools.</summary> public HttpConnectionPoolManager(HttpConnectionSettings settings) { _settings = settings; _maxConnectionsPerServer = settings._maxConnectionsPerServer; _pools = new ConcurrentDictionary <HttpConnectionKey, HttpConnectionPool>(); // As an optimization, we can sometimes avoid the overheads associated with // storing connections. This is possible when we would immediately terminate // connections anyway due to either the idle timeout or the lifetime being // set to zero, as in that case the timeout effectively immediately expires. // However, we can only do such optimizations if we're not also tracking // connections per server, as we use data in the associated data structures // to do that tracking. bool avoidStoringConnections = settings._maxConnectionsPerServer == int.MaxValue && (settings._pooledConnectionIdleTimeout == TimeSpan.Zero || settings._pooledConnectionLifetime == TimeSpan.Zero); // Start out with the timer not running, since we have no pools. // When it does run, run it with a frequency based on the idle timeout. if (!avoidStoringConnections) { if (settings._pooledConnectionIdleTimeout == Timeout.InfiniteTimeSpan) { const int DefaultScavengeSeconds = 30; _cleanPoolTimeout = TimeSpan.FromSeconds(DefaultScavengeSeconds); } else { const int ScavengesPerIdle = 4; const int MinScavengeSeconds = 1; TimeSpan timerPeriod = settings._pooledConnectionIdleTimeout / ScavengesPerIdle; _cleanPoolTimeout = timerPeriod.TotalSeconds >= MinScavengeSeconds ? timerPeriod : TimeSpan.FromSeconds(MinScavengeSeconds); } bool restoreFlow = false; try { // Don't capture the current ExecutionContext and its AsyncLocals onto the timer causing them to live forever if (!ExecutionContext.IsFlowSuppressed()) { ExecutionContext.SuppressFlow(); restoreFlow = true; } // Create the timer. Ensure the Timer has a weak reference to this manager; otherwise, it // can introduce a cycle that keeps the HttpConnectionPoolManager rooted by the Timer // implementation until the handler is Disposed (or indefinitely if it's not). var thisRef = new WeakReference <HttpConnectionPoolManager>(this); _cleaningTimer = new Timer(static s =>
public static byte[] BuildSettingsFrame(HttpConnectionSettings settings) { Span <byte> buffer = stackalloc byte[4 + VariableLengthIntegerHelper.MaximumEncodedLength]; int integerLength = VariableLengthIntegerHelper.WriteInteger(buffer.Slice(4), settings._maxResponseHeadersLength * 1024L); int payloadLength = 1 + integerLength; // includes the setting ID and the integer value. Debug.Assert(payloadLength <= VariableLengthIntegerHelper.OneByteLimit); buffer[0] = (byte)Http3StreamType.Control; buffer[1] = (byte)Http3FrameType.Settings; buffer[2] = (byte)payloadLength; buffer[3] = (byte)Http3SettingType.MaxHeaderListSize; return(buffer.Slice(4 + integerLength).ToArray()); }
public static async ValueTask <SslStream> EstablishSslConnectionAsync(HttpConnectionSettings settings, string host, HttpRequestMessage request, Stream stream, CancellationToken cancellationToken) { RemoteCertificateValidationCallback callback = null; if (settings._serverCertificateCustomValidationCallback != null) { callback = (object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) => { try { return(settings._serverCertificateCustomValidationCallback(request, certificate as X509Certificate2, chain, sslPolicyErrors)); } catch (Exception e) { throw new HttpRequestException(SR.net_http_ssl_connection_failed, e); } }; } var sslStream = new SslStream(stream); try { await sslStream.AuthenticateAsClientAsync(new SslClientAuthenticationOptions { TargetHost = host, ClientCertificates = settings._clientCertificates, EnabledSslProtocols = settings._sslProtocols, CertificateRevocationCheckMode = settings._checkCertificateRevocationList ? X509RevocationMode.Online : X509RevocationMode.NoCheck, RemoteCertificateValidationCallback = callback }, cancellationToken).ConfigureAwait(false); } catch (Exception e) { sslStream.Dispose(); if (e is AuthenticationException || e is IOException) { throw new HttpRequestException(SR.net_http_ssl_connection_failed, e); } throw; } return(sslStream); }
public static async ValueTask <SslStream> EstablishSslConnectionAsync(HttpConnectionSettings settings, string host, HttpRequestMessage request, Stream stream, CancellationToken cancellationToken) { // Create the options bag to use. Since we mutate it, we don't just use the shared instance. SslClientAuthenticationOptions sslOptions; if (settings._sslOptions != null) { sslOptions = settings._sslOptions.ShallowClone(); sslOptions.ApplicationProtocols = null; // explicitly ignore any ApplicationProtocols set } else { sslOptions = new SslClientAuthenticationOptions(); } // Use the specified host, regardless of what was provided. sslOptions.TargetHost = host; // If there's a cert validation callback, and if it came from HttpClientHandler, // wrap the original delegate in order to change the sender to be the request message (expected by HttpClientHandler's delegate). RemoteCertificateValidationCallback callback = sslOptions.RemoteCertificateValidationCallback; if (callback != null && callback.Target is CertificateCallbackMapper mapper) { Func <HttpRequestMessage, X509Certificate2, X509Chain, SslPolicyErrors, bool> fromHttpClientHandler = mapper.FromHttpClientHandler; HttpRequestMessage localRequest = request; sslOptions.RemoteCertificateValidationCallback = (object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) => fromHttpClientHandler(localRequest, certificate as X509Certificate2, chain, sslPolicyErrors); } // Create the SslStream, authenticate, and return it. var sslStream = new SslStream(stream); try { await sslStream.AuthenticateAsClientAsync(sslOptions, cancellationToken).ConfigureAwait(false); } catch (Exception e) { sslStream.Dispose(); throw new HttpRequestException(SR.net_http_ssl_connection_failed, e); } return(sslStream); }
public HttpConnectionHandler(HttpConnectionSettings settings) { _settings = settings; _connectionPools = new HttpConnectionPools(settings._maxConnectionsPerServer); }
public HttpConnectionHandler(HttpConnectionSettings settings) { _connectionPools = new HttpConnectionPools(settings, usingProxy: false); }
/// <summary>Initializes the pools.</summary> public HttpConnectionPoolManager(HttpConnectionSettings settings) { _settings = settings; _maxConnectionsPerServer = settings._maxConnectionsPerServer; _avoidStoringConnections = settings._pooledConnectionIdleTimeout == TimeSpan.Zero || settings._pooledConnectionLifetime == TimeSpan.Zero; _pools = new ConcurrentDictionary <HttpConnectionKey, HttpConnectionPool>(); // Start out with the timer not running, since we have no pools. // When it does run, run it with a frequency based on the idle timeout. if (!_avoidStoringConnections) { if (settings._pooledConnectionIdleTimeout == Timeout.InfiniteTimeSpan) { const int DefaultScavengeSeconds = 30; _cleanPoolTimeout = TimeSpan.FromSeconds(DefaultScavengeSeconds); } else { const int ScavengesPerIdle = 4; const int MinScavengeSeconds = 1; TimeSpan timerPeriod = new TimeSpan(settings._pooledConnectionIdleTimeout.Ticks / ScavengesPerIdle); _cleanPoolTimeout = timerPeriod.TotalSeconds >= MinScavengeSeconds ? timerPeriod : TimeSpan.FromSeconds(MinScavengeSeconds); } bool restoreFlow = false; try { // Don't capture the current ExecutionContext and its AsyncLocals onto the timer causing them to live forever if (!ExecutionContext.IsFlowSuppressed()) { ExecutionContext.SuppressFlow(); restoreFlow = true; } // Create the timer. Ensure the Timer has a weak reference to this manager; otherwise, it // can introduce a cycle that keeps the HttpConnectionPoolManager rooted by the Timer // implementation until the handler is Disposed (or indefinitely if it's not). _cleaningTimer = new Timer(s => { var wr = (WeakReference <HttpConnectionPoolManager>)s; if (wr.TryGetTarget(out HttpConnectionPoolManager thisRef)) { thisRef.RemoveStalePools(); } }, new WeakReference <HttpConnectionPoolManager>(this), Timeout.Infinite, Timeout.Infinite); } finally { // Restore the current ExecutionContext if (restoreFlow) { ExecutionContext.RestoreFlow(); } } } // Figure out proxy stuff. if (settings._useProxy) { _proxy = settings._proxy; if (_proxy != null) { _proxyCredentials = _proxy.Credentials ?? settings._defaultProxyCredentials; } } }
/// <summary>Initializes the pools.</summary> public HttpConnectionPoolManager(HttpConnectionSettings settings) { _settings = settings; _maxConnectionsPerServer = settings._maxConnectionsPerServer; _pools = new ConcurrentDictionary <HttpConnectionKey, HttpConnectionPool>(); // As an optimization, we can sometimes avoid the overheads associated with // storing connections. This is possible when we would immediately terminate // connections anyway due to either the idle timeout or the lifetime being // set to zero, as in that case the timeout effectively immediately expires. // However, we can only do such optimizations if we're not also tracking // connections per server, as we use data in the associated data structures // to do that tracking. bool avoidStoringConnections = settings._maxConnectionsPerServer == int.MaxValue && (settings._pooledConnectionIdleTimeout == TimeSpan.Zero || settings._pooledConnectionLifetime == TimeSpan.Zero); // Start out with the timer not running, since we have no pools. // When it does run, run it with a frequency based on the idle timeout. if (!avoidStoringConnections) { if (settings._pooledConnectionIdleTimeout == Timeout.InfiniteTimeSpan) { const int DefaultScavengeSeconds = 30; _cleanPoolTimeout = TimeSpan.FromSeconds(DefaultScavengeSeconds); } else { const int ScavengesPerIdle = 4; const int MinScavengeSeconds = 1; TimeSpan timerPeriod = settings._pooledConnectionIdleTimeout / ScavengesPerIdle; _cleanPoolTimeout = timerPeriod.TotalSeconds >= MinScavengeSeconds ? timerPeriod : TimeSpan.FromSeconds(MinScavengeSeconds); } bool restoreFlow = false; try { // Don't capture the current ExecutionContext and its AsyncLocals onto the timer causing them to live forever if (!ExecutionContext.IsFlowSuppressed()) { ExecutionContext.SuppressFlow(); restoreFlow = true; } // Create the timer. Ensure the Timer has a weak reference to this manager; otherwise, it // can introduce a cycle that keeps the HttpConnectionPoolManager rooted by the Timer // implementation until the handler is Disposed (or indefinitely if it's not). _cleaningTimer = new Timer(s => { var wr = (WeakReference <HttpConnectionPoolManager>)s; if (wr.TryGetTarget(out HttpConnectionPoolManager thisRef)) { thisRef.RemoveStalePools(); } }, new WeakReference <HttpConnectionPoolManager>(this), Timeout.Infinite, Timeout.Infinite); } finally { // Restore the current ExecutionContext if (restoreFlow) { ExecutionContext.RestoreFlow(); } } } // Figure out proxy stuff. if (settings._useProxy) { _proxy = settings._proxy ?? HttpClient.DefaultProxy; if (_proxy != null) { _proxyCredentials = _proxy.Credentials ?? settings._defaultProxyCredentials; } } // Monitor network changes to invalidate Alt-Svc headers. // A weak reference is used to avoid NetworkChange.NetworkAddressChanged keeping a non-disposed connection pool alive. var poolsRef = new WeakReference <ConcurrentDictionary <HttpConnectionKey, HttpConnectionPool> >(_pools); NetworkAddressChangedEventHandler networkChangedDelegate = null; networkChangedDelegate = delegate { if (poolsRef.TryGetTarget(out ConcurrentDictionary <HttpConnectionKey, HttpConnectionPool> pools)) { foreach (HttpConnectionPool pool in pools.Values) { pool.OnNetworkChanged(); } } else { // Our pools were GCed; user did not dispose the handler. NetworkChange.NetworkAddressChanged -= networkChangedDelegate; } }; _networkChangedDelegate = networkChangedDelegate; using (ExecutionContext.SuppressFlow()) { NetworkChange.NetworkAddressChanged += networkChangedDelegate; } }
public HttpConnectionHandler(HttpConnectionSettings settings) { _connectionPools = new HttpConnectionPools(settings, settings._maxConnectionsPerServer, usingProxy: false); }
/// <summary>Initializes the pools.</summary> public HttpConnectionPoolManager(HttpConnectionSettings settings) { _settings = settings; _maxConnectionsPerServer = settings._maxConnectionsPerServer; _pools = new ConcurrentDictionary <HttpConnectionKey, HttpConnectionPool>(); // As an optimization, we can sometimes avoid the overheads associated with // storing connections. This is possible when we would immediately terminate // connections anyway due to either the idle timeout or the lifetime being // set to zero, as in that case the timeout effectively immediately expires. // However, we can only do such optimizations if we're not also tracking // connections per server, as we use data in the associated data structures // to do that tracking. bool avoidStoringConnections = settings._maxConnectionsPerServer == int.MaxValue && (settings._pooledConnectionIdleTimeout == TimeSpan.Zero || settings._pooledConnectionLifetime == TimeSpan.Zero); // Start out with the timer not running, since we have no pools. // When it does run, run it with a frequency based on the idle timeout. if (!avoidStoringConnections) { if (settings._pooledConnectionIdleTimeout == Timeout.InfiniteTimeSpan) { const int DefaultScavengeSeconds = 30; _cleanPoolTimeout = TimeSpan.FromSeconds(DefaultScavengeSeconds); } else { const int ScavengesPerIdle = 4; const int MinScavengeSeconds = 1; TimeSpan timerPeriod = settings._pooledConnectionIdleTimeout / ScavengesPerIdle; _cleanPoolTimeout = timerPeriod.TotalSeconds >= MinScavengeSeconds ? timerPeriod : TimeSpan.FromSeconds(MinScavengeSeconds); } bool restoreFlow = false; try { // Don't capture the current ExecutionContext and its AsyncLocals onto the timer causing them to live forever if (!ExecutionContext.IsFlowSuppressed()) { ExecutionContext.SuppressFlow(); restoreFlow = true; } _cleaningTimer = new Timer(s => ((HttpConnectionPoolManager)s).RemoveStalePools(), this, Timeout.Infinite, Timeout.Infinite); } finally { // Restore the current ExecutionContext if (restoreFlow) { ExecutionContext.RestoreFlow(); } } } // Figure out proxy stuff. if (settings._useProxy) { _proxy = settings._proxy ?? SystemProxyInfo.ConstructSystemProxy(); if (_proxy != null) { _proxyCredentials = _proxy.Credentials ?? settings._defaultProxyCredentials; } } }