33// See the LICENSE file in the project root for more information.
44
55using System . Collections . Generic ;
6+ using System . Diagnostics ;
67using System . Net . Http . Headers ;
78using System . Threading ;
89using System . Threading . Tasks ;
@@ -12,11 +13,11 @@ namespace System.Net.Http
1213{
1314 internal partial class AuthenticationHelper
1415 {
15- private static Task < HttpResponseMessage > InnerSendAsync ( HttpRequestMessage request , bool isProxyAuth , HttpConnection connection , CancellationToken cancellationToken )
16+ private static Task < HttpResponseMessage > InnerSendAsync ( HttpRequestMessage request , bool isProxyAuth , HttpConnectionPool pool , HttpConnection connection , CancellationToken cancellationToken )
1617 {
1718 return isProxyAuth ?
1819 connection . SendAsyncCore ( request , cancellationToken ) :
19- connection . SendWithNtProxyAuthAsync ( request , cancellationToken ) ;
20+ pool . SendWithNtProxyAuthAsync ( connection , request , cancellationToken ) ;
2021 }
2122
2223 private static bool ProxySupportsConnectionAuth ( HttpResponseMessage response )
@@ -37,9 +38,9 @@ private static bool ProxySupportsConnectionAuth(HttpResponseMessage response)
3738 return false ;
3839 }
3940
40- private static async Task < HttpResponseMessage > SendWithNtAuthAsync ( HttpRequestMessage request , Uri authUri , ICredentials credentials , bool isProxyAuth , HttpConnection connection , CancellationToken cancellationToken )
41+ private static async Task < HttpResponseMessage > SendWithNtAuthAsync ( HttpRequestMessage request , Uri authUri , ICredentials credentials , bool isProxyAuth , HttpConnection connection , HttpConnectionPool connectionPool , CancellationToken cancellationToken )
4142 {
42- HttpResponseMessage response = await InnerSendAsync ( request , isProxyAuth , connection , cancellationToken ) . ConfigureAwait ( false ) ;
43+ HttpResponseMessage response = await InnerSendAsync ( request , isProxyAuth , connectionPool , connection , cancellationToken ) . ConfigureAwait ( false ) ;
4344 if ( ! isProxyAuth && connection . Kind == HttpConnectionKind . Proxy && ! ProxySupportsConnectionAuth ( response ) )
4445 {
4546 // Proxy didn't indicate that it supports connection-based auth, so we can't proceed.
@@ -55,51 +56,80 @@ private static async Task<HttpResponseMessage> SendWithNtAuthAsync(HttpRequestMe
5556 if ( challenge . AuthenticationType == AuthenticationType . Negotiate ||
5657 challenge . AuthenticationType == AuthenticationType . Ntlm )
5758 {
58- string challengeData = challenge . ChallengeData ;
59-
60- string spn = "HTTP/" + authUri . IdnHost ;
61- ChannelBinding channelBinding = connection . TransportContext ? . GetChannelBinding ( ChannelBindingKind . Endpoint ) ;
62- NTAuthentication authContext = new NTAuthentication ( isServer : false , challenge . SchemeName , challenge . Credential , spn , ContextFlagsPal . Connection , channelBinding ) ;
59+ bool isNewConnection = false ;
6360 try
6461 {
65- while ( true )
62+ if ( response . Headers . ConnectionClose . GetValueOrDefault ( ) )
6663 {
67- string challengeResponse = authContext . GetOutgoingBlob ( challengeData ) ;
68- if ( challengeResponse == null )
64+ // Server is closing the connection and asking us to authenticate on a new connection.
65+ ( connection , response ) = await connectionPool . CreateHttp11ConnectionAsync ( request , cancellationToken ) . ConfigureAwait ( false ) ;
66+ if ( response != null )
6967 {
70- // Response indicated denial even after login, so stop processing and return current response.
71- break ;
68+ return response ;
7269 }
7370
71+ connectionPool . IncrementConnectionCount ( ) ;
72+ connection . Acquire ( ) ;
73+ isNewConnection = true ;
74+ }
75+ else
76+ {
7477 await connection . DrainResponseAsync ( response ) . ConfigureAwait ( false ) ;
78+ }
7579
76- SetRequestAuthenticationHeaderValue ( request , new AuthenticationHeaderValue ( challenge . SchemeName , challengeResponse ) , isProxyAuth ) ;
80+ string challengeData = challenge . ChallengeData ;
7781
78- response = await InnerSendAsync ( request , isProxyAuth , connection , cancellationToken ) . ConfigureAwait ( false ) ;
79- if ( authContext . IsCompleted || ! TryGetRepeatedChallenge ( response , challenge . SchemeName , isProxyAuth , out challengeData ) )
82+ string spn = "HTTP/" + authUri . IdnHost ;
83+ ChannelBinding channelBinding = connection . TransportContext ? . GetChannelBinding ( ChannelBindingKind . Endpoint ) ;
84+ NTAuthentication authContext = new NTAuthentication ( isServer : false , challenge . SchemeName , challenge . Credential , spn , ContextFlagsPal . Connection , channelBinding ) ;
85+ try
86+ {
87+ while ( true )
8088 {
81- break ;
89+ string challengeResponse = authContext . GetOutgoingBlob ( challengeData ) ;
90+ if ( challengeResponse == null )
91+ {
92+ // Response indicated denial even after login, so stop processing and return current response.
93+ break ;
94+ }
95+
96+ SetRequestAuthenticationHeaderValue ( request , new AuthenticationHeaderValue ( challenge . SchemeName , challengeResponse ) , isProxyAuth ) ;
97+
98+ response = await InnerSendAsync ( request , isProxyAuth , connectionPool , connection , cancellationToken ) . ConfigureAwait ( false ) ;
99+ if ( authContext . IsCompleted || ! TryGetRepeatedChallenge ( response , challenge . SchemeName , isProxyAuth , out challengeData ) )
100+ {
101+ break ;
102+ }
103+
104+ await connection . DrainResponseAsync ( response ) . ConfigureAwait ( false ) ;
82105 }
83106 }
107+ finally
108+ {
109+ authContext . CloseContext ( ) ;
110+ }
84111 }
85112 finally
86113 {
87- authContext . CloseContext ( ) ;
114+ if ( isNewConnection )
115+ {
116+ connection . Release ( ) ;
117+ }
88118 }
89119 }
90120 }
91121
92122 return response ;
93123 }
94124
95- public static Task < HttpResponseMessage > SendWithNtProxyAuthAsync ( HttpRequestMessage request , Uri proxyUri , ICredentials proxyCredentials , HttpConnection connection , CancellationToken cancellationToken )
125+ public static Task < HttpResponseMessage > SendWithNtProxyAuthAsync ( HttpRequestMessage request , Uri proxyUri , ICredentials proxyCredentials , HttpConnection connection , HttpConnectionPool connectionPool , CancellationToken cancellationToken )
96126 {
97- return SendWithNtAuthAsync ( request , proxyUri , proxyCredentials , isProxyAuth : true , connection , cancellationToken ) ;
127+ return SendWithNtAuthAsync ( request , proxyUri , proxyCredentials , isProxyAuth : true , connection , connectionPool , cancellationToken ) ;
98128 }
99129
100- public static Task < HttpResponseMessage > SendWithNtConnectionAuthAsync ( HttpRequestMessage request , ICredentials credentials , HttpConnection connection , CancellationToken cancellationToken )
130+ public static Task < HttpResponseMessage > SendWithNtConnectionAuthAsync ( HttpRequestMessage request , ICredentials credentials , HttpConnection connection , HttpConnectionPool connectionPool , CancellationToken cancellationToken )
101131 {
102- return SendWithNtAuthAsync ( request , request . RequestUri , credentials , isProxyAuth : false , connection , cancellationToken ) ;
132+ return SendWithNtAuthAsync ( request , request . RequestUri , credentials , isProxyAuth : false , connection , connectionPool , cancellationToken ) ;
103133 }
104134 }
105135}
0 commit comments