1212using CURLoption = Interop . libcurl . CURLoption ;
1313using CURLcode = Interop . libcurl . CURLcode ;
1414using CURLINFO = Interop . libcurl . CURLINFO ;
15+ using CURLProxyType = Interop . libcurl . curl_proxytype ;
1516
1617namespace System . Net . Http
1718{
@@ -20,14 +21,17 @@ internal class CurlHandler : HttpMessageHandler
2021 #region Constants
2122
2223 private const string UriSchemeHttps = "https" ;
23-
24+ private readonly static string [ ] AuthenticationSchemes = { "Negotiate" , "Digest" , "Basic" } ; // the order in which libcurl goes over authentication schemes
2425 #endregion
2526
2627 #region Fields
2728
2829 private volatile bool _anyOperationStarted ;
2930 private volatile bool _disposed ;
3031 private bool _automaticRedirection = true ;
32+ private IWebProxy _proxy = null ;
33+ private ICredentials _serverCredentials = null ;
34+ private ProxyUsePolicy _proxyPolicy = ProxyUsePolicy . UseDefaultProxy ;
3135
3236 #endregion
3337
@@ -50,6 +54,59 @@ internal bool AutomaticRedirection
5054 }
5155 }
5256
57+ internal bool SupportsProxy
58+ {
59+ get
60+ {
61+ return true ;
62+ }
63+ }
64+
65+ internal bool UseProxy
66+ {
67+ get
68+ {
69+ return _proxyPolicy != ProxyUsePolicy . DoNotUseProxy ;
70+ }
71+ set
72+ {
73+ CheckDisposedOrStarted ( ) ;
74+ if ( value )
75+ {
76+ _proxyPolicy = ProxyUsePolicy . UseCustomProxy ;
77+ }
78+ else
79+ {
80+ _proxyPolicy = ProxyUsePolicy . DoNotUseProxy ;
81+ }
82+ }
83+ }
84+
85+ internal IWebProxy Proxy
86+ {
87+ get
88+ {
89+ return _proxy ;
90+ }
91+ set
92+ {
93+ CheckDisposedOrStarted ( ) ;
94+ _proxy = value ;
95+ }
96+ }
97+
98+ internal ICredentials Credentials
99+ {
100+ get
101+ {
102+ return _serverCredentials ;
103+ }
104+ set
105+ {
106+ CheckDisposedOrStarted ( ) ;
107+ _serverCredentials = value ;
108+ }
109+ }
53110 #endregion
54111
55112 protected override void Dispose ( bool disposing )
@@ -175,11 +232,83 @@ private SafeCurlHandle CreateRequestHandle(RequestCompletionSource state)
175232 Interop . libcurl . curl_easy_setopt ( requestHandle , CURLoption . CURLOPT_FOLLOWLOCATION , 1 ) ;
176233 }
177234
178- // TODO: Handle headers, proxy and other options
235+ SetProxyOptions ( state , requestHandle ) ;
236+ // TODO: Handle headers and other options
179237
180238 return requestHandle ;
181239 }
182240
241+ private static void SetProxyOptions ( RequestCompletionSource state , SafeCurlHandle requestHandle )
242+ {
243+ var requestUri = state . RequestMessage . RequestUri ;
244+ Debug . Assert ( state . Handler != null ) ;
245+ if ( state . Handler . _proxyPolicy == ProxyUsePolicy . DoNotUseProxy )
246+ {
247+ Interop . libcurl . curl_easy_setopt ( requestHandle , CURLoption . CURLOPT_PROXY , string . Empty ) ;
248+ return ;
249+ }
250+
251+ if ( ( state . Handler . _proxyPolicy == ProxyUsePolicy . UseDefaultProxy ) || ( state . Handler . Proxy == null ) )
252+ {
253+ return ;
254+ }
255+
256+ Debug . Assert ( ( state . Handler . Proxy != null ) && ( state . Handler . _proxyPolicy == ProxyUsePolicy . UseCustomProxy ) ) ;
257+ if ( state . Handler . Proxy . IsBypassed ( requestUri ) )
258+ {
259+ Interop . libcurl . curl_easy_setopt ( requestHandle , CURLoption . CURLOPT_PROXY , string . Empty ) ;
260+ return ;
261+ }
262+
263+ var proxyUri = state . Handler . Proxy . GetProxy ( requestUri ) ;
264+ if ( proxyUri == null )
265+ {
266+ return ;
267+ }
268+
269+ Interop . libcurl . curl_easy_setopt ( requestHandle , CURLoption . CURLOPT_PROXYTYPE , CURLProxyType . CURLPROXY_HTTP ) ;
270+ Interop . libcurl . curl_easy_setopt ( requestHandle , CURLoption . CURLOPT_PROXY , proxyUri . AbsoluteUri ) ;
271+ Interop . libcurl . curl_easy_setopt ( requestHandle , CURLoption . CURLOPT_PROXYPORT , proxyUri . Port ) ;
272+ NetworkCredential credentials = GetCredentials ( state . Handler . Proxy . Credentials , requestUri ) ;
273+ if ( credentials != null )
274+ {
275+ if ( string . IsNullOrEmpty ( credentials . UserName ) )
276+ {
277+ throw new ArgumentException ( SR . net_http_argument_empty_string , "UserName" ) ;
278+ }
279+
280+ string credentialText ;
281+ if ( string . IsNullOrEmpty ( credentials . Domain ) )
282+ {
283+ credentialText = string . Format ( "{0}:{1}" , credentials . UserName , credentials . Password ) ;
284+ }
285+ else
286+ {
287+ credentialText = string . Format ( "{2}\\ {0}:{1}" , credentials . UserName , credentials . Password , credentials . Domain ) ;
288+ }
289+ Interop . libcurl . curl_easy_setopt ( requestHandle , CURLoption . CURLOPT_PROXYUSERPWD , credentialText ) ;
290+ }
291+ }
292+
293+ private static NetworkCredential GetCredentials ( ICredentials proxyCredentials , Uri requestUri )
294+ {
295+ if ( proxyCredentials == null )
296+ {
297+ return null ;
298+ }
299+
300+ foreach ( var authScheme in AuthenticationSchemes )
301+ {
302+ NetworkCredential proxyCreds = proxyCredentials . GetCredential ( requestUri , authScheme ) ;
303+ if ( proxyCreds != null )
304+ {
305+ return proxyCreds ;
306+ }
307+ }
308+
309+ return null ;
310+ }
311+
183312 private HttpResponseMessage CreateResponseMessage ( SafeCurlHandle requestHandle , HttpRequestMessage request )
184313 {
185314 var response = new HttpResponseMessage ( ) ;
@@ -190,7 +319,7 @@ private HttpResponseMessage CreateResponseMessage(SafeCurlHandle requestHandle,
190319 {
191320 throw new HttpRequestException ( SR . net_http_client_execution_error , GetCurlException ( result ) ) ;
192321 }
193- response . StatusCode = ( HttpStatusCode ) httpStatusCode ;
322+ response . StatusCode = ( HttpStatusCode ) httpStatusCode ;
194323
195324 // TODO: Do error processing if needed and return actual response
196325 response . Content =
@@ -255,5 +384,13 @@ private sealed class RequestCompletionSource : TaskCompletionSource<HttpResponse
255384
256385 public CurlHandler Handler { get ; set ; }
257386 }
387+
388+ private enum ProxyUsePolicy
389+ {
390+ DoNotUseProxy = 0 , // Do not use proxy. Ignores the value set in the environment.
391+ UseDefaultProxy = 1 , // Do not set the proxy parameter. Use the value of environment variable, if any.
392+ UseCustomProxy = 2 // Use The proxy specified by the user.
393+ }
258394 }
259395}
396+
0 commit comments