Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Commit 20eea48

Browse files
committed
Introducing checks for libcurl features
Runtime and load-time checks to ensure that the features user is relying on are available in the libcurl library loaded
1 parent cda0ae1 commit 20eea48

File tree

4 files changed

+70
-3
lines changed

4 files changed

+70
-3
lines changed

src/Common/src/Interop/Unix/libcurl/Interop.libcurl.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,5 +140,8 @@ public static extern IntPtr curl_slist_append(
140140
[DllImport(Interop.Libraries.LibCurl)]
141141
public static extern void curl_slist_free_all(
142142
IntPtr curl_slist);
143+
144+
[DllImport(Interop.Libraries.LibCurl)]
145+
public static extern IntPtr curl_version_info(int curlVersionStamp);
143146
}
144147
}

src/Common/src/Interop/Unix/libcurl/Interop.libcurl_types.cs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,30 @@ internal static partial class CURLMSG
125125
internal const int CURLMSG_DONE = 1;
126126
}
127127

128+
internal static partial class CURL_VERSION_Features
129+
{
130+
internal const int CURL_VERSION_IPV6 = (1<<0);
131+
internal const int CURL_VERSION_KERBEROS4 = (1<<1);
132+
internal const int CURL_VERSION_SSL = (1<<2);
133+
internal const int CURL_VERSION_LIBZ = (1<<3);
134+
internal const int CURL_VERSION_NTLM = (1<<4);
135+
internal const int CURL_VERSION_GSSNEGOTIATE = (1<<5);
136+
internal const int CURL_VERSION_DEBUG = (1<<6);
137+
internal const int CURL_VERSION_ASYNCHDNS = (1<<7);
138+
internal const int CURL_VERSION_SPNEGO = (1<<8);
139+
internal const int CURL_VERSION_LARGEFILE = (1<<9);
140+
internal const int CURL_VERSION_IDN = (1<<10);
141+
internal const int CURL_VERSION_SSPI = (1<<11);
142+
internal const int CURL_VERSION_CONV = (1<<12);
143+
internal const int CURL_VERSION_CURLDEBUG = (1<<13);
144+
internal const int CURL_VERSION_TLSAUTH_SRP = (1<<14);
145+
internal const int CURL_VERSION_NTLM_WB = (1<<15);
146+
internal const int CURL_VERSION_HTTP2 = (1<<16);
147+
internal const int CURL_VERSION_GSSAPI = (1<<17);
148+
internal const int CURL_VERSION_KERBEROS5 = (1<<18);
149+
internal const int CURL_VERSION_UNIX_SOCKETS = (1<<19);
150+
}
151+
128152
// Type definition of CURLMsg from multi.h
129153
[StructLayout(LayoutKind.Explicit)]
130154
internal struct CURLMsg
@@ -139,6 +163,16 @@ internal struct CURLMsg
139163
internal int result;
140164
}
141165

166+
// Curl Version Information
167+
[StructLayout(LayoutKind.Explicit)]
168+
internal struct curl_version_info_data
169+
{
170+
[FieldOffset(0)]
171+
internal int age;
172+
[FieldOffset(32)]
173+
internal int features;
174+
}
175+
142176
public delegate int curl_socket_callback(
143177
IntPtr handle,
144178
curl_socket_t sockfd,

src/System.Net.Http/src/Resources/Strings.resx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,4 +288,10 @@
288288
<data name="net_http_unix_invalid_client_cert_option" xml:space="preserve">
289289
<value>libcurl supports only manual client certificate selection</value>
290290
</data>
291+
<data name="net_http_unix_https_libcurl_too_old" xml:space="preserve">
292+
<value>libcurl library available is too old</value>
293+
</data>
294+
<data name="net_http_unix_https_support_unavailable_libcurl" xml:space="preserve">
295+
<value>libcurl library available on the system does not support https</value>
296+
</data>
291297
</root>

src/System.Net.Http/src/System/Net/Http/Unix/CurlHandler.cs

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,12 @@
1919
using CURLcode = Interop.libcurl.CURLcode;
2020
using CURLMcode = Interop.libcurl.CURLMcode;
2121
using CURLINFO = Interop.libcurl.CURLINFO;
22+
using CurlVersionInfoData = Interop.libcurl.curl_version_info_data;
23+
using CurlFeatures = Interop.libcurl.CURL_VERSION_Features;
2224
using CURLProxyType = Interop.libcurl.curl_proxytype;
2325
using size_t = System.IntPtr;
2426

27+
2528
namespace System.Net.Http
2629
{
2730
internal partial class CurlHandler : HttpMessageHandler
@@ -34,13 +37,19 @@ internal partial class CurlHandler : HttpMessageHandler
3437
private const string EncodingNameDeflate = "deflate";
3538
private readonly static string[] AuthenticationSchemes = { "Negotiate", "Digest", "Basic" }; // the order in which libcurl goes over authentication schemes
3639
private static readonly string[] s_headerDelimiters = new string[] { "\r\n" };
40+
3741
private const int s_requestBufferSize = 16384; // Default used by libcurl
3842
private const string NoTransferEncoding = HttpKnownHeaderNames.TransferEncoding + ":";
43+
private readonly static CurlVersionInfoData curlVersionInfoData;
44+
private const int CurlAge = 5;
45+
private const int MinCurlAge = 3;
3946

4047
#endregion
4148

4249
#region Fields
43-
50+
51+
private static bool _supportsAutomaticDecompression;
52+
private static bool _supportsSSL;
4453
private volatile bool _anyOperationStarted;
4554
private volatile bool _disposed;
4655
private IWebProxy _proxy = null;
@@ -63,6 +72,13 @@ static CurlHandler()
6372
{
6473
throw new InvalidOperationException("Cannot use libcurl in this process");
6574
}
75+
curlVersionInfoData = Marshal.PtrToStructure<CurlVersionInfoData>(Interop.libcurl.curl_version_info(CurlAge));
76+
if (curlVersionInfoData.age < MinCurlAge)
77+
{
78+
throw new InvalidOperationException(SR.net_http_unix_https_libcurl_too_old);
79+
}
80+
_supportsSSL = (CurlFeatures.CURL_VERSION_SSL & curlVersionInfoData.features) != 0;
81+
_supportsAutomaticDecompression = (CurlFeatures.CURL_VERSION_LIBZ & curlVersionInfoData.features) != 0;
6682
}
6783

6884
internal CurlHandler()
@@ -168,7 +184,7 @@ internal bool SupportsAutomaticDecompression
168184
{
169185
get
170186
{
171-
return true;
187+
return _supportsAutomaticDecompression;
172188
}
173189
}
174190

@@ -267,6 +283,11 @@ protected internal override Task<HttpResponseMessage> SendAsync(
267283
throw NotImplemented.ByDesignWithMessage(SR.net_http_client_http_baseaddress_required);
268284
}
269285

286+
if (request.RequestUri.Scheme == UriSchemeHttps && !_supportsSSL)
287+
{
288+
throw new PlatformNotSupportedException(SR.net_http_unix_https_support_unavailable_libcurl);
289+
}
290+
270291
if (request.Headers.TransferEncodingChunked.GetValueOrDefault() && (request.Content == null))
271292
{
272293
throw new InvalidOperationException(SR.net_http_chunked_not_allowed_with_empty_content);
@@ -427,7 +448,10 @@ private SafeCurlHandle CreateRequestHandle(RequestCompletionSource state, GCHand
427448

428449
SetCurlCallbacks(requestHandle, state.RequestMessage, statePtr);
429450

430-
SetRequestHandleDecompressionOptions(requestHandle);
451+
if (_supportsAutomaticDecompression)
452+
{
453+
SetRequestHandleDecompressionOptions(requestHandle);
454+
}
431455

432456
SetProxyOptions(requestHandle, state.RequestMessage.RequestUri);
433457

0 commit comments

Comments
 (0)