11using System ;
22using System . IO ;
3+ using System . Linq ;
34using System . Net ;
5+ using System . Net . Http ;
46using System . Net . Security ;
7+ using System . Security . Authentication ;
58using System . Security . Cryptography . X509Certificates ;
69
710namespace LibGit2Sharp . Core
@@ -49,12 +52,36 @@ private class ManagedHttpSmartSubtransportStream : SmartSubtransportStream
4952 private MemoryStream postBuffer = new MemoryStream ( ) ;
5053 private Stream responseStream ;
5154
55+ private HttpClientHandler httpClientHandler ;
56+ private HttpClient httpClient ;
57+
5258 public ManagedHttpSmartSubtransportStream ( ManagedHttpSmartSubtransport parent , string endpointUrl , bool isPost , string contentType )
5359 : base ( parent )
5460 {
5561 EndpointUrl = new Uri ( endpointUrl ) ;
5662 IsPost = isPost ;
5763 ContentType = contentType ;
64+
65+ httpClientHandler = CreateClientHandler ( ) ;
66+ httpClient = new HttpClient ( httpClientHandler ) ;
67+ }
68+
69+ private HttpClientHandler CreateClientHandler ( )
70+ {
71+ #if ! NETFRAMEWORK
72+ var httpClientHandler = new HttpClientHandler ( ) ;
73+ httpClientHandler . SslProtocols |= SslProtocols . Tls12 ;
74+ httpClientHandler . ServerCertificateCustomValidationCallback = CertificateValidationProxy ;
75+ #else
76+ var httpClientHandler = new WebRequestHandler ( ) ;
77+ httpClientHandler . ServerCertificateValidationCallback = CertificateValidationProxy ;
78+
79+ ServicePointManager . SecurityProtocol |= SecurityProtocolType . Tls12 ;
80+ #endif
81+
82+ httpClientHandler . AllowAutoRedirect = false ;
83+
84+ return httpClientHandler ;
5885 }
5986
6087 private Uri EndpointUrl
@@ -104,13 +131,21 @@ public override int Write(Stream dataStream, long length)
104131
105132 private bool CertificateValidationProxy ( object sender , X509Certificate cert , X509Chain chain , SslPolicyErrors errors )
106133 {
107- int ret = SmartTransport . CertificateCheck ( new CertificateX509 ( cert ) , ( errors == SslPolicyErrors . None ) , EndpointUrl . Host ) ;
108- Ensure . ZeroResult ( ret ) ;
134+ try
135+ {
136+ int ret = SmartTransport . CertificateCheck ( new CertificateX509 ( cert ) , ( errors == SslPolicyErrors . None ) , EndpointUrl . Host ) ;
137+ Ensure . ZeroResult ( ret ) ;
109138
110- return true ;
139+ return true ;
140+ }
141+ catch ( Exception e )
142+ {
143+ SetError ( e ) ;
144+ return false ;
145+ }
111146 }
112147
113- private string getUserAgent ( )
148+ private string GetUserAgent ( )
114149 {
115150 string userAgent = GlobalSettings . GetUserAgent ( ) ;
116151
@@ -122,97 +157,76 @@ private string getUserAgent()
122157 return userAgent ;
123158 }
124159
125- private HttpWebRequest CreateWebRequest ( Uri endpointUrl , bool isPost , string contentType )
160+ private HttpRequestMessage CreateRequest ( Uri endpointUrl , bool isPost , string contentType )
126161 {
127- ServicePointManager . SecurityProtocol = SecurityProtocolType . Tls12 ;
128-
129- HttpWebRequest webRequest = ( HttpWebRequest ) HttpWebRequest . Create ( endpointUrl ) ;
130- webRequest . UserAgent = String . Format ( "git/2.0 ({0})" , getUserAgent ( ) ) ;
131- webRequest . ServicePoint . Expect100Continue = false ;
132- webRequest . AllowAutoRedirect = false ;
133- webRequest . ServerCertificateValidationCallback += CertificateValidationProxy ;
162+ var verb = isPost ? new HttpMethod ( "POST" ) : new HttpMethod ( "GET" ) ;
163+ var request = new HttpRequestMessage ( verb , endpointUrl ) ;
164+ request . Headers . Add ( "User-Agent" , String . Format ( "git/2.0 ({0})" , GetUserAgent ( ) ) ) ;
165+ request . Headers . Remove ( "Expect" ) ;
134166
135- if ( isPost )
136- {
137- webRequest . Method = "POST" ;
138- webRequest . ContentType = contentType ;
139- }
140-
141- return webRequest ;
167+ return request ;
142168 }
143169
144- private HttpWebResponse GetResponseWithRedirects ( )
170+ private HttpResponseMessage GetResponseWithRedirects ( )
145171 {
146- HttpWebRequest request = CreateWebRequest ( EndpointUrl , IsPost , ContentType ) ;
147- HttpWebResponse response = null ;
172+ ICredentials credentials = null ;
173+ var url = EndpointUrl ;
148174 int retries ;
149175
150176 for ( retries = 0 ; ; retries ++ )
151177 {
152- if ( retries > MAX_REDIRECTS )
153- {
154- throw new Exception ( "too many redirects or authentication replays" ) ;
155- }
178+ var httpClientHandler = CreateClientHandler ( ) ;
179+ httpClientHandler . Credentials = credentials ;
156180
157- if ( IsPost && postBuffer . Length > 0 )
181+ using ( var httpClient = new HttpClient ( httpClientHandler ) )
158182 {
159- postBuffer . Seek ( 0 , SeekOrigin . Begin ) ;
183+ var request = CreateRequest ( url , IsPost , ContentType ) ;
160184
161- using ( Stream requestStream = request . GetRequestStream ( ) )
185+ if ( retries > MAX_REDIRECTS )
162186 {
163- postBuffer . WriteTo ( requestStream ) ;
187+ throw new Exception ( "too many redirects or authentication replays" ) ;
164188 }
165- }
166189
167- try
168- {
169- response = ( HttpWebResponse ) request . GetResponse ( ) ;
170- }
171- catch ( WebException ex )
172- {
173- if ( ex . Response != null )
190+ if ( IsPost && postBuffer . Length > 0 )
174191 {
175- response = ( HttpWebResponse ) ex . Response ;
192+ var bufferDup = new MemoryStream ( postBuffer . GetBuffer ( ) ) ;
193+ bufferDup . Seek ( 0 , SeekOrigin . Begin ) ;
194+
195+ request . Content = new StreamContent ( bufferDup ) ;
196+ request . Content . Headers . Add ( "Content-Type" , ContentType ) ;
176197 }
177- else if ( ex . InnerException != null )
198+
199+ var response = httpClient . SendAsync ( request ) . Result ;
200+
201+ if ( response . StatusCode == HttpStatusCode . OK )
178202 {
179- throw ex . InnerException ;
203+ return response ;
180204 }
181- else
205+ else if ( response . StatusCode == HttpStatusCode . Unauthorized )
182206 {
183- throw new Exception ( "unknown network failure" ) ;
184- }
185- }
207+ Credentials cred ;
208+ int ret = SmartTransport . AcquireCredentials ( out cred , null , typeof ( UsernamePasswordCredentials ) ) ;
186209
187- if ( response . StatusCode == HttpStatusCode . OK )
188- {
189- break ;
190- }
191- else if ( response . StatusCode == HttpStatusCode . Unauthorized )
192- {
193- Credentials cred ;
194- int ret = SmartTransport . AcquireCredentials ( out cred , null , typeof ( UsernamePasswordCredentials ) ) ;
210+ if ( ret != 0 )
211+ {
212+ throw new InvalidOperationException ( "authentication cancelled" ) ;
213+ }
195214
196- if ( ret != 0 )
215+ UsernamePasswordCredentials userpass = ( UsernamePasswordCredentials ) cred ;
216+ credentials = new NetworkCredential ( userpass . Username , userpass . Password ) ;
217+ continue ;
218+ }
219+ else if ( response . StatusCode == HttpStatusCode . Moved || response . StatusCode == HttpStatusCode . Redirect )
197220 {
198- throw new InvalidOperationException ( "authentication cancelled" ) ;
221+ url = new Uri ( response . Headers . GetValues ( "Location" ) . First ( ) ) ;
222+ continue ;
199223 }
200224
201- request = CreateWebRequest ( EndpointUrl , IsPost , ContentType ) ;
202- UsernamePasswordCredentials userpass = ( UsernamePasswordCredentials ) cred ;
203- request . Credentials = new NetworkCredential ( userpass . Username , userpass . Password ) ;
204- continue ;
205- }
206- else if ( response . StatusCode == HttpStatusCode . Moved || response . StatusCode == HttpStatusCode . Redirect )
207- {
208- request = CreateWebRequest ( new Uri ( response . Headers [ "Location" ] ) , IsPost , ContentType ) ;
209- continue ;
225+ throw new Exception ( string . Format ( "unexpected HTTP response: {0}" , response . StatusCode ) ) ;
210226 }
211-
212- throw new Exception ( string . Format ( "unexpected HTTP response: {0}" , response . StatusCode ) ) ;
213227 }
214228
215- return response ;
229+ throw new Exception ( "too many redirects or authentication replays" ) ;
216230 }
217231
218232 public override int Read ( Stream dataStream , long length , out long readTotal )
@@ -222,8 +236,8 @@ public override int Read(Stream dataStream, long length, out long readTotal)
222236
223237 if ( responseStream == null )
224238 {
225- HttpWebResponse response = GetResponseWithRedirects ( ) ;
226- responseStream = response . GetResponseStream ( ) ;
239+ HttpResponseMessage response = GetResponseWithRedirects ( ) ;
240+ responseStream = response . Content . ReadAsStreamAsync ( ) . Result ;
227241 }
228242
229243 while ( length > 0 )
@@ -249,6 +263,12 @@ protected override void Free()
249263 responseStream = null ;
250264 }
251265
266+ if ( httpClient != null )
267+ {
268+ httpClient . Dispose ( ) ;
269+ httpClient = null ;
270+ }
271+
252272 base . Free ( ) ;
253273 }
254274 }
0 commit comments