|
| 1 | +using System; |
1 | 2 | using System.Net.Http; |
| 3 | +using System.Net.Security; |
| 4 | +using System.Security.Cryptography.X509Certificates; |
| 5 | +using GeneralUpdate.Core.Security; |
2 | 6 |
|
3 | 7 | namespace GeneralUpdate.Core.Network; |
4 | 8 |
|
5 | 9 | /// <summary> |
6 | | -/// Provides a shared static <see cref="HttpClient"/> instance. |
| 10 | +/// Provides a shared static <see cref="HttpClient"/> instance with configurable SSL validation. |
7 | 11 | /// Reusing a single HttpClient prevents socket exhaustion. |
8 | 12 | /// Do NOT dispose clients obtained from here. |
9 | 13 | /// </summary> |
| 14 | +/// <remarks> |
| 15 | +/// <para> |
| 16 | +/// SSL certificate validation behaviour is controlled by the |
| 17 | +/// <see cref="SetSslValidationPolicy"/> method. The default policy is |
| 18 | +/// <see cref="StrictSslValidationPolicy"/> (rejects any certificate with SSL errors). |
| 19 | +/// </para> |
| 20 | +/// <para> |
| 21 | +/// This class mirrors the SSL validation pattern used by <see cref="VersionService"/>, |
| 22 | +/// ensuring that both API calls and file downloads respect the same global SSL policy. |
| 23 | +/// </para> |
| 24 | +/// </remarks> |
10 | 25 | public static class HttpClientProvider |
11 | 26 | { |
12 | | - private static readonly HttpClient _shared = new(); |
| 27 | + private static ISslValidationPolicy _sslPolicy = new StrictSslValidationPolicy(); |
| 28 | + private static readonly HttpClient _shared; |
| 29 | + |
| 30 | + static HttpClientProvider() |
| 31 | + { |
| 32 | + var handler = new HttpClientHandler(); |
| 33 | + handler.ServerCertificateCustomValidationCallback = (req, cert, chain, errors) => |
| 34 | + _sslPolicy.ValidateCertificate(cert, chain, errors); |
| 35 | + _shared = new HttpClient(handler, disposeHandler: false) |
| 36 | + { |
| 37 | + // Let per-request CancellationTokenSource.CancelAfter (set by |
| 38 | + // HttpDownloadExecutor & VersionService) control timeout — the |
| 39 | + // global HttpClient.Timeout (default ~100s) would otherwise cap |
| 40 | + // requests before a caller-configured longer DownloadTimeout. |
| 41 | + Timeout = System.Threading.Timeout.InfiniteTimeSpan |
| 42 | + }; |
| 43 | + } |
| 44 | + |
| 45 | + /// <summary> |
| 46 | + /// Sets the global SSL certificate validation policy for all download requests. |
| 47 | + /// </summary> |
| 48 | + /// <param name="policy">The SSL validation policy instance. Must not be null.</param> |
| 49 | + /// <exception cref="ArgumentNullException">Thrown when <paramref name="policy"/> is null.</exception> |
| 50 | + /// <remarks> |
| 51 | + /// <para> |
| 52 | + /// This policy affects all HTTPS download requests made through |
| 53 | + /// <see cref="HttpDownloadExecutor"/> and other components that use the shared |
| 54 | + /// <see cref="HttpClient"/>. The default is <see cref="StrictSslValidationPolicy"/>. |
| 55 | + /// </para> |
| 56 | + /// <para> |
| 57 | + /// The validation callback delegates to the stored policy instance, so the policy |
| 58 | + /// can be changed at any time — new requests will use the updated policy. |
| 59 | + /// </para> |
| 60 | + /// </remarks> |
| 61 | + public static void SetSslValidationPolicy(ISslValidationPolicy policy) |
| 62 | + => _sslPolicy = policy ?? throw new ArgumentNullException(nameof(policy)); |
13 | 63 |
|
14 | 64 | /// <summary> |
15 | 65 | /// Gets the shared <see cref="HttpClient"/> instance. Do NOT dispose. |
|
0 commit comments