66using System . Diagnostics . CodeAnalysis ;
77using System . Globalization ;
88using System . IO ;
9+ using System . Net ;
910using System . Net . Cache ;
1011using System . Net . Http ;
1112using System . Net . Http . Headers ;
@@ -41,6 +42,7 @@ public class HttpWebRequest : WebRequest, ISerializable
4142 private Task < HttpResponseMessage > ? _sendRequestTask ;
4243
4344 private static int _defaultMaxResponseHeadersLength = HttpHandlerDefaults . DefaultMaxResponseHeadersLength ;
45+ private static int _defaultMaximumErrorResponseLength = - 1 ;
4446
4547 private int _beginGetRequestStreamCalled ;
4648 private int _beginGetResponseCalled ;
@@ -420,11 +422,7 @@ public string? Referer
420422 /// <devdoc>
421423 /// <para>Sets the media type header</para>
422424 /// </devdoc>
423- public string ? MediaType
424- {
425- get ;
426- set ;
427- }
425+ public string ? MediaType { get ; set ; }
428426
429427 /// <devdoc>
430428 /// <para>
@@ -677,14 +675,22 @@ public static int DefaultMaximumResponseHeadersLength
677675 }
678676 set
679677 {
678+ ArgumentOutOfRangeException . ThrowIfLessThan ( value , 0 ) ;
680679 _defaultMaxResponseHeadersLength = value ;
681680 }
682681 }
683682
684- // NOP
685683 public static int DefaultMaximumErrorResponseLength
686684 {
687- get ; set ;
685+ get
686+ {
687+ return _defaultMaximumErrorResponseLength ;
688+ }
689+ set
690+ {
691+ ArgumentOutOfRangeException . ThrowIfLessThan ( value , - 1 ) ;
692+ _defaultMaximumErrorResponseLength = value ;
693+ }
688694 }
689695
690696 private static RequestCachePolicy ? _defaultCachePolicy = new RequestCachePolicy ( RequestCacheLevel . BypassCache ) ;
@@ -806,10 +812,12 @@ public Version ProtocolVersion
806812 if ( value . Equals ( HttpVersion . Version11 ) )
807813 {
808814 IsVersionHttp10 = false ;
815+ ServicePoint . ProtocolVersion = HttpVersion . Version11 ;
809816 }
810817 else if ( value . Equals ( HttpVersion . Version10 ) )
811818 {
812819 IsVersionHttp10 = true ;
820+ ServicePoint . ProtocolVersion = HttpVersion . Version10 ;
813821 }
814822 else
815823 {
@@ -1621,6 +1629,13 @@ private static HttpClient CreateHttpClient(HttpClientParameters parameters, Http
16211629 handler . UseCookies = false ;
16221630 }
16231631
1632+ if ( parameters . ServicePoint is { } servicePoint )
1633+ {
1634+ handler . MaxConnectionsPerServer = servicePoint . ConnectionLimit ;
1635+ handler . PooledConnectionIdleTimeout = TimeSpan . FromMilliseconds ( servicePoint . MaxIdleTime ) ;
1636+ handler . PooledConnectionLifetime = TimeSpan . FromMilliseconds ( servicePoint . ConnectionLeaseTimeout ) ;
1637+ }
1638+
16241639 Debug . Assert ( handler . UseProxy ) ; // Default of handler.UseProxy is true.
16251640 Debug . Assert ( handler . Proxy == null ) ; // Default of handler.Proxy is null.
16261641
@@ -1638,7 +1653,7 @@ private static HttpClient CreateHttpClient(HttpClientParameters parameters, Http
16381653 {
16391654 handler . UseProxy = false ;
16401655 }
1641- else if ( ! object . ReferenceEquals ( parameters . Proxy , WebRequest . GetSystemWebProxy ( ) ) )
1656+ else if ( ! ReferenceEquals ( parameters . Proxy , GetSystemWebProxy ( ) ) )
16421657 {
16431658 handler . Proxy = parameters . Proxy ;
16441659 }
@@ -1659,10 +1674,20 @@ private static HttpClient CreateHttpClient(HttpClientParameters parameters, Http
16591674 handler . SslOptions . EnabledSslProtocols = ( SslProtocols ) parameters . SslProtocols ;
16601675 handler . SslOptions . CertificateRevocationCheckMode = parameters . CheckCertificateRevocationList ? X509RevocationMode . Online : X509RevocationMode . NoCheck ;
16611676 RemoteCertificateValidationCallback ? rcvc = parameters . ServerCertificateValidationCallback ;
1662- if ( rcvc != null )
1677+ handler . SslOptions . RemoteCertificateValidationCallback = ( message , cert , chain , errors ) =>
16631678 {
1664- handler . SslOptions . RemoteCertificateValidationCallback = ( message , cert , chain , errors ) => rcvc ( request ! , cert , chain , errors ) ;
1665- }
1679+ if ( parameters . ServicePoint is { } servicePoint )
1680+ {
1681+ servicePoint . Certificate = cert ;
1682+ }
1683+
1684+ if ( rcvc is not null )
1685+ {
1686+ return rcvc ( request ! , cert , chain , errors ) ;
1687+ }
1688+
1689+ return errors == SslPolicyErrors . None ;
1690+ } ;
16661691
16671692 // Set up a ConnectCallback so that we can control Socket-specific settings, like ReadWriteTimeout => socket.Send/ReceiveTimeout.
16681693 handler . ConnectCallback = async ( context , cancellationToken ) =>
@@ -1671,6 +1696,10 @@ private static HttpClient CreateHttpClient(HttpClientParameters parameters, Http
16711696
16721697 try
16731698 {
1699+ IPAddress [ ] addresses = parameters . Async ?
1700+ await Dns . GetHostAddressesAsync ( context . DnsEndPoint . Host , cancellationToken ) . ConfigureAwait ( false ) :
1701+ Dns . GetHostAddresses ( context . DnsEndPoint . Host ) ;
1702+
16741703 if ( parameters . ServicePoint is { } servicePoint )
16751704 {
16761705 if ( servicePoint . ReceiveBufferSize != - 1 )
@@ -1684,19 +1713,58 @@ private static HttpClient CreateHttpClient(HttpClientParameters parameters, Http
16841713 socket . SetSocketOption ( SocketOptionLevel . Tcp , SocketOptionName . TcpKeepAliveTime , keepAlive . Time ) ;
16851714 socket . SetSocketOption ( SocketOptionLevel . Tcp , SocketOptionName . TcpKeepAliveInterval , keepAlive . Interval ) ;
16861715 }
1716+
1717+ BindHelper ( servicePoint , ref addresses , socket , context . DnsEndPoint . Port ) ;
1718+ static void BindHelper ( ServicePoint servicePoint , ref IPAddress [ ] addresses , Socket socket , int port )
1719+ {
1720+ if ( servicePoint . BindIPEndPointDelegate is null )
1721+ {
1722+ return ;
1723+ }
1724+
1725+ const int MaxRetries = 100 ;
1726+ foreach ( IPAddress address in addresses )
1727+ {
1728+ int retryCount = 0 ;
1729+ for ( ; retryCount < MaxRetries ; retryCount ++ )
1730+ {
1731+ IPEndPoint ? endPoint = servicePoint . BindIPEndPointDelegate ( servicePoint , new IPEndPoint ( address , port ) , retryCount ) ;
1732+ if ( endPoint is null ) // Get other address to try
1733+ {
1734+ break ;
1735+ }
1736+
1737+ try
1738+ {
1739+ socket . Bind ( endPoint ) ;
1740+ addresses = [ address ] ;
1741+ return ; // Bind successful, exit loops.
1742+ }
1743+ catch
1744+ {
1745+ continue ;
1746+ }
1747+ }
1748+
1749+ if ( retryCount >= MaxRetries )
1750+ {
1751+ throw new OverflowException ( SR . net_maximumbindretries ) ;
1752+ }
1753+ }
1754+ }
16871755 }
16881756
1689- socket . NoDelay = true ;
1757+ socket . NoDelay = ! ( parameters . ServicePoint ? . UseNagleAlgorithm ) ?? true ;
16901758
16911759 if ( parameters . Async )
16921760 {
1693- await socket . ConnectAsync ( context . DnsEndPoint , cancellationToken ) . ConfigureAwait ( false ) ;
1761+ await socket . ConnectAsync ( addresses , context . DnsEndPoint . Port , cancellationToken ) . ConfigureAwait ( false ) ;
16941762 }
16951763 else
16961764 {
16971765 using ( cancellationToken . UnsafeRegister ( s => ( ( Socket ) s ! ) . Dispose ( ) , socket ) )
16981766 {
1699- socket . Connect ( context . DnsEndPoint ) ;
1767+ socket . Connect ( addresses , context . DnsEndPoint . Port ) ;
17001768 }
17011769
17021770 // Throw in case cancellation caused the socket to be disposed after the Connect completed
0 commit comments