12
12
using CURLoption = Interop . libcurl . CURLoption ;
13
13
using CURLcode = Interop . libcurl . CURLcode ;
14
14
using CURLINFO = Interop . libcurl . CURLINFO ;
15
+ using CURLProxyType = Interop . libcurl . curl_proxytype ;
15
16
16
17
namespace System . Net . Http
17
18
{
@@ -20,14 +21,17 @@ internal class CurlHandler : HttpMessageHandler
20
21
#region Constants
21
22
22
23
private const string UriSchemeHttps = "https" ;
23
-
24
+ private readonly static string [ ] AuthenticationSchemes = { "Negotiate" , "Digest" , "Basic" } ; // the order in which libcurl goes over authentication schemes
24
25
#endregion
25
26
26
27
#region Fields
27
28
28
29
private volatile bool _anyOperationStarted ;
29
30
private volatile bool _disposed ;
30
31
private bool _automaticRedirection = true ;
32
+ private IWebProxy _proxy = null ;
33
+ private ICredentials _serverCredentials = null ;
34
+ private ProxyUsePolicy _proxyPolicy = ProxyUsePolicy . UseDefaultProxy ;
31
35
32
36
#endregion
33
37
@@ -50,6 +54,59 @@ internal bool AutomaticRedirection
50
54
}
51
55
}
52
56
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
+ }
53
110
#endregion
54
111
55
112
protected override void Dispose ( bool disposing )
@@ -175,11 +232,83 @@ private SafeCurlHandle CreateRequestHandle(RequestCompletionSource state)
175
232
Interop . libcurl . curl_easy_setopt ( requestHandle , CURLoption . CURLOPT_FOLLOWLOCATION , 1 ) ;
176
233
}
177
234
178
- // TODO: Handle headers, proxy and other options
235
+ SetProxyOptions ( state , requestHandle ) ;
236
+ // TODO: Handle headers and other options
179
237
180
238
return requestHandle ;
181
239
}
182
240
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
+
183
312
private HttpResponseMessage CreateResponseMessage ( SafeCurlHandle requestHandle , HttpRequestMessage request )
184
313
{
185
314
var response = new HttpResponseMessage ( ) ;
@@ -190,7 +319,7 @@ private HttpResponseMessage CreateResponseMessage(SafeCurlHandle requestHandle,
190
319
{
191
320
throw new HttpRequestException ( SR . net_http_client_execution_error , GetCurlException ( result ) ) ;
192
321
}
193
- response . StatusCode = ( HttpStatusCode ) httpStatusCode ;
322
+ response . StatusCode = ( HttpStatusCode ) httpStatusCode ;
194
323
195
324
// TODO: Do error processing if needed and return actual response
196
325
response . Content =
@@ -255,5 +384,13 @@ private sealed class RequestCompletionSource : TaskCompletionSource<HttpResponse
255
384
256
385
public CurlHandler Handler { get ; set ; }
257
386
}
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
+ }
258
394
}
259
395
}
396
+
0 commit comments