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,34 @@ 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+ var httpClientHandler = new HttpClientHandler ( ) ;
72+
73+ httpClientHandler . AllowAutoRedirect = false ;
74+ httpClientHandler . ServerCertificateCustomValidationCallback = CertificateValidationProxy ;
75+
76+ #if ! NETFRAMEWORK
77+ httpClientHandler . SslProtocols = SslProtocols . Tls12 ;
78+ #else
79+ ServicePointManager . SecurityProtocol = SecurityProtocolType . Tls12 ;
80+ #endif
81+
82+ return httpClientHandler ;
5883 }
5984
6085 private Uri EndpointUrl
@@ -104,13 +129,21 @@ public override int Write(Stream dataStream, long length)
104129
105130 private bool CertificateValidationProxy ( object sender , X509Certificate cert , X509Chain chain , SslPolicyErrors errors )
106131 {
107- int ret = SmartTransport . CertificateCheck ( new CertificateX509 ( cert ) , ( errors == SslPolicyErrors . None ) , EndpointUrl . Host ) ;
108- Ensure . ZeroResult ( ret ) ;
132+ try
133+ {
134+ int ret = SmartTransport . CertificateCheck ( new CertificateX509 ( cert ) , ( errors == SslPolicyErrors . None ) , EndpointUrl . Host ) ;
135+ Ensure . ZeroResult ( ret ) ;
109136
110- return true ;
137+ return true ;
138+ }
139+ catch ( Exception e )
140+ {
141+ SetError ( e ) ;
142+ return false ;
143+ }
111144 }
112145
113- private string getUserAgent ( )
146+ private string GetUserAgent ( )
114147 {
115148 string userAgent = GlobalSettings . GetUserAgent ( ) ;
116149
@@ -122,97 +155,76 @@ private string getUserAgent()
122155 return userAgent ;
123156 }
124157
125- private HttpWebRequest CreateWebRequest ( Uri endpointUrl , bool isPost , string contentType )
158+ private HttpRequestMessage CreateRequest ( Uri endpointUrl , bool isPost , string contentType )
126159 {
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 ;
160+ var verb = isPost ? new HttpMethod ( "POST" ) : new HttpMethod ( "GET" ) ;
161+ var request = new HttpRequestMessage ( verb , endpointUrl ) ;
162+ request . Headers . Add ( "User-Agent" , String . Format ( "git/2.0 ({0})" , GetUserAgent ( ) ) ) ;
163+ request . Headers . Remove ( "Expect" ) ;
134164
135- if ( isPost )
136- {
137- webRequest . Method = "POST" ;
138- webRequest . ContentType = contentType ;
139- }
140-
141- return webRequest ;
165+ return request ;
142166 }
143167
144- private HttpWebResponse GetResponseWithRedirects ( )
168+ private HttpResponseMessage GetResponseWithRedirects ( )
145169 {
146- HttpWebRequest request = CreateWebRequest ( EndpointUrl , IsPost , ContentType ) ;
147- HttpWebResponse response = null ;
170+ ICredentials credentials = null ;
171+ var url = EndpointUrl ;
148172 int retries ;
149173
150174 for ( retries = 0 ; ; retries ++ )
151175 {
152- if ( retries > MAX_REDIRECTS )
153- {
154- throw new Exception ( "too many redirects or authentication replays" ) ;
155- }
176+ var httpClientHandler = CreateClientHandler ( ) ;
177+ httpClientHandler . Credentials = credentials ;
156178
157- if ( IsPost && postBuffer . Length > 0 )
179+ using ( var httpClient = new HttpClient ( httpClientHandler ) )
158180 {
159- postBuffer . Seek ( 0 , SeekOrigin . Begin ) ;
181+ var request = CreateRequest ( url , IsPost , ContentType ) ;
160182
161- using ( Stream requestStream = request . GetRequestStream ( ) )
183+ if ( retries > MAX_REDIRECTS )
162184 {
163- postBuffer . WriteTo ( requestStream ) ;
185+ throw new Exception ( "too many redirects or authentication replays" ) ;
164186 }
165- }
166187
167- try
168- {
169- response = ( HttpWebResponse ) request . GetResponse ( ) ;
170- }
171- catch ( WebException ex )
172- {
173- if ( ex . Response != null )
188+ if ( IsPost && postBuffer . Length > 0 )
174189 {
175- response = ( HttpWebResponse ) ex . Response ;
190+ var bufferDup = new MemoryStream ( postBuffer . GetBuffer ( ) ) ;
191+ bufferDup . Seek ( 0 , SeekOrigin . Begin ) ;
192+
193+ request . Content = new StreamContent ( bufferDup ) ;
194+ request . Content . Headers . Add ( "Content-Type" , ContentType ) ;
176195 }
177- else if ( ex . InnerException != null )
196+
197+ var response = httpClient . SendAsync ( request ) . Result ;
198+
199+ if ( response . StatusCode == HttpStatusCode . OK )
178200 {
179- throw ex . InnerException ;
201+ return response ;
180202 }
181- else
203+ else if ( response . StatusCode == HttpStatusCode . Unauthorized )
182204 {
183- throw new Exception ( "unknown network failure" ) ;
184- }
185- }
205+ Credentials cred ;
206+ int ret = SmartTransport . AcquireCredentials ( out cred , null , typeof ( UsernamePasswordCredentials ) ) ;
186207
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 ) ) ;
208+ if ( ret != 0 )
209+ {
210+ throw new InvalidOperationException ( "authentication cancelled" ) ;
211+ }
195212
196- if ( ret != 0 )
213+ UsernamePasswordCredentials userpass = ( UsernamePasswordCredentials ) cred ;
214+ credentials = new NetworkCredential ( userpass . Username , userpass . Password ) ;
215+ continue ;
216+ }
217+ else if ( response . StatusCode == HttpStatusCode . Moved || response . StatusCode == HttpStatusCode . Redirect )
197218 {
198- throw new InvalidOperationException ( "authentication cancelled" ) ;
219+ url = new Uri ( response . Headers . GetValues ( "Location" ) . First ( ) ) ;
220+ continue ;
199221 }
200222
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 ;
223+ throw new Exception ( string . Format ( "unexpected HTTP response: {0}" , response . StatusCode ) ) ;
210224 }
211-
212- throw new Exception ( string . Format ( "unexpected HTTP response: {0}" , response . StatusCode ) ) ;
213225 }
214226
215- return response ;
227+ throw new Exception ( "too many redirects or authentication replays" ) ;
216228 }
217229
218230 public override int Read ( Stream dataStream , long length , out long readTotal )
@@ -222,8 +234,8 @@ public override int Read(Stream dataStream, long length, out long readTotal)
222234
223235 if ( responseStream == null )
224236 {
225- HttpWebResponse response = GetResponseWithRedirects ( ) ;
226- responseStream = response . GetResponseStream ( ) ;
237+ HttpResponseMessage response = GetResponseWithRedirects ( ) ;
238+ responseStream = ( response . Content as StreamContent ) . ReadAsStreamAsync ( ) . Result ;
227239 }
228240
229241 while ( length > 0 )
@@ -249,6 +261,12 @@ protected override void Free()
249261 responseStream = null ;
250262 }
251263
264+ if ( httpClient != null )
265+ {
266+ httpClient . Dispose ( ) ;
267+ httpClient = null ;
268+ }
269+
252270 base . Free ( ) ;
253271 }
254272 }
0 commit comments