Darabonba/Utils/HttpClientUtils.cs (150 lines of code) (raw):
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Text;
namespace Darabonba.Utils
{
public static class HttpClientUtils
{
public static Func<object , X509Certificate2Collection, System.Security.Cryptography.X509Certificates.X509Certificate, X509Chain, SslPolicyErrors, bool> ServerCertificateCustomValidationCallback { get; set; }
internal static ConcurrentDictionary<string, HttpClient> httpClients = new ConcurrentDictionary<string, HttpClient>();
internal static HttpClient GetOrAddHttpClient(string protocol,string host, int port, Dictionary<string, object> options)
{
string key;
string proxyUrl = options.Get("httpProxy") != null ? options.Get("httpProxy").ToSafeString() : options.Get("httpsProxy").ToSafeString();
if(!string.IsNullOrWhiteSpace(proxyUrl))
{
Uri uri = new Uri(proxyUrl);
key = string.Format("{0}:{1}:{2}", protocol, uri.Host, uri.Port);
}
else
{
key = string.Format("{0}:{1}:{2}", protocol, host, port);
}
HttpClient httpClient = (HttpClient)httpClients.Get(key);
if(httpClient == null)
{
httpClient = CreatHttpClient(options);
httpClients[key] = httpClient;
}
return httpClient;
}
internal static HttpClient CreatHttpClient(Dictionary<string, object> options)
{
HttpClient httpClient;
string proxyUrl = options.Get("httpProxy") != null ? options.Get("httpProxy").ToSafeString() : options.Get("httpsProxy").ToSafeString();
bool ignoreSSL = options.Get("ignoreSSL").ToSafeBool(false);
#if NET45
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3
| SecurityProtocolType.Tls
| SecurityProtocolType.Tls11
| SecurityProtocolType.Tls12;
var handler = new WebRequestHandler();
if(!string.IsNullOrWhiteSpace(proxyUrl))
{
handler.Proxy = new WebProxy(new Uri(proxyUrl));
}
else
{
handler.UseProxy = false;
}
if(ignoreSSL)
{
handler.ServerCertificateValidationCallback = delegate { return true; };
}
else
{
string ca = options.Get("ca") != null ? options.Get("ca").ToSafeString() : options.Get("ca").ToSafeString();
if (!string.IsNullOrWhiteSpace(ca))
{
handler.ServerCertificateValidationCallback = (message, cert, chain, sslPolicyErrors) =>
{
var collection = new X509Certificate2Collection();
byte[] certBytes = Encoding.UTF8.GetBytes(ca);
X509Certificate2 cacert = new X509Certificate2(certBytes);
collection.Add(cacert);
if (ServerCertificateCustomValidationCallback != null)
{
return ServerCertificateCustomValidationCallback(message, collection, cert, chain, sslPolicyErrors);
}
return CertificateValidationCallBack(message, collection, cert, chain, sslPolicyErrors);
};
}
}
httpClient = new HttpClient(handler);
#else
HttpClientHandler httpClientHandler = new HttpClientHandler();
if (!string.IsNullOrWhiteSpace(proxyUrl))
{
httpClientHandler.Proxy = new WebProxy(new Uri(proxyUrl));
}
else
{
httpClientHandler.UseProxy = false;
}
if (ignoreSSL)
{
httpClientHandler.ServerCertificateCustomValidationCallback = (message, cert, chain, error) => true;
}
else
{
string ca = options.Get("ca") != null ? options.Get("ca").ToSafeString() : options.Get("ca").ToSafeString();
if(!string.IsNullOrWhiteSpace(ca))
{
httpClientHandler.ServerCertificateCustomValidationCallback = (message, cert, chain, sslPolicyErrors) =>
{
var collection = new X509Certificate2Collection();
byte[] certBytes = Encoding.UTF8.GetBytes(ca);
X509Certificate2 cacert = new X509Certificate2(certBytes);
collection.Add(cacert);
if (ServerCertificateCustomValidationCallback != null)
{
return ServerCertificateCustomValidationCallback(message, collection, cert, chain, sslPolicyErrors);
}
return CertificateValidationCallBack(message, collection, cert, chain, sslPolicyErrors);
};
}
}
httpClient = new HttpClient(httpClientHandler);
#endif
return httpClient;
}
public static bool CertificateValidationCallBack(
object sender,
X509Certificate2Collection caCerts,
System.Security.Cryptography.X509Certificates.X509Certificate certificate,
X509Chain chain,
SslPolicyErrors sslPolicyErrors)
{
// If the certificate is a valid, signed certificate, return true.
if (sslPolicyErrors == SslPolicyErrors.None)
{
return true;
}
// If there are errors in the certificate chain, look at each error to determine the cause.
if ((sslPolicyErrors & SslPolicyErrors.RemoteCertificateChainErrors) != 0)
{
chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
// Added our trusted certificates to the chain
//
chain.ChainPolicy.ExtraStore.AddRange(caCerts);
chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllowUnknownCertificateAuthority;
var isValid = chain.Build((X509Certificate2)certificate);
var isTrusted = false;
var rootCert = chain.ChainElements[chain.ChainElements.Count - 1].Certificate;
// Make sure that one of our trusted certs exists in the chain provided by the server.
//
foreach (var cert in caCerts)
{
if (rootCert.RawData.SequenceEqual(cert.RawData))
{
isTrusted = true;
break;
}
}
return isValid && isTrusted;
}
// In all other cases, return false.
return false;
}
}
}