-
Notifications
You must be signed in to change notification settings - Fork 282
HttpClient fixes for Container port and SSL validation #2688
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
6c0e627
4f3aef0
a2153d7
79891bb
627b830
6eaa4c2
a94c802
29b9622
bc7c411
dd60ae7
6228b90
ea27bb9
670ae44
3491fdc
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -48,6 +48,7 @@ | |
| using Microsoft.Extensions.Hosting; | ||
| using Microsoft.Extensions.Logging; | ||
| using Microsoft.Extensions.Options; | ||
| using Microsoft.Extensions.Primitives; | ||
| using NodaTime; | ||
| using OpenTelemetry.Exporter; | ||
| using OpenTelemetry.Logs; | ||
|
|
@@ -272,22 +273,44 @@ public void ConfigureServices(IServiceCollection services) | |
| services.AddHttpClient("ContextConfiguredHealthCheckClient") | ||
| .ConfigureHttpClient((serviceProvider, client) => | ||
| { | ||
| IHttpContextAccessor httpContextAccessor = serviceProvider.GetRequiredService<IHttpContextAccessor>(); | ||
| HttpContext? httpContext = httpContextAccessor.HttpContext; | ||
| IHttpContextAccessor httpCtxAccessor = serviceProvider.GetRequiredService<IHttpContextAccessor>(); | ||
| HttpContext? httpContext = httpCtxAccessor.HttpContext; | ||
| string baseUri = string.Empty; | ||
|
|
||
| if (httpContext != null) | ||
| if (httpContext is not null) | ||
| { | ||
| // Build base address from request | ||
| string baseUri = $"{httpContext.Request.Scheme}://{httpContext.Request.Host}"; | ||
| string scheme = httpContext.Request.Scheme; // "http" or "https" | ||
| string host = httpContext.Request.Host.Host ?? "localhost"; // e.g. "localhost" | ||
| int port = ResolveInternalPort(httpContext); | ||
| baseUri = $"{scheme}://{host}:{port}"; | ||
| client.BaseAddress = new Uri(baseUri); | ||
| } | ||
| else | ||
| { | ||
| // Optional fallback if ever needed in non-request scenarios | ||
| baseUri = $"http://localhost:{ResolveInternalPort()}"; | ||
| client.BaseAddress = new Uri(baseUri); | ||
|
|
||
| // Set default Accept header | ||
| client.DefaultRequestHeaders.Accept.Clear(); | ||
| client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); | ||
| } | ||
|
|
||
| // Optional: Set a timeout | ||
| _logger.LogInformation($"Configured HealthCheck HttpClient BaseAddress as: {baseUri}"); | ||
| client.DefaultRequestHeaders.Accept.Clear(); | ||
| client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); | ||
| client.Timeout = TimeSpan.FromSeconds(200); | ||
| }) | ||
| .ConfigurePrimaryHttpMessageHandler(serviceProvider => | ||
| { | ||
| // For debug purpose, USE_SELF_SIGNED_CERT can be set to true in Environment variables | ||
| bool allowSelfSigned = Environment.GetEnvironmentVariable("USE_SELF_SIGNED_CERT")?.Equals("true", StringComparison.OrdinalIgnoreCase) == true; | ||
|
|
||
| HttpClientHandler handler = new(); | ||
|
|
||
| if (allowSelfSigned) | ||
| { | ||
| handler.ServerCertificateCustomValidationCallback = | ||
| HttpClientHandler.DangerousAcceptAnyServerCertificateValidator; | ||
| } | ||
|
|
||
| return handler; | ||
| }); | ||
|
|
||
| if (runtimeConfig is not null && runtimeConfig.Runtime?.Host?.Mode is HostMode.Development) | ||
|
|
@@ -941,5 +964,59 @@ public static void AddValidFilters() | |
| LoggerFilters.AddFilter(typeof(IAuthorizationResolver).FullName); | ||
| LoggerFilters.AddFilter("default"); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Get the internal port of the container. | ||
| /// </summary> | ||
| /// <param name="httpContext">The HttpContext</param> | ||
| /// <returns>The internal container port</returns> | ||
| private static int ResolveInternalPort(HttpContext? httpContext = null) | ||
| { | ||
| // Try X-Forwarded-Port if context is present | ||
| if (httpContext is not null && | ||
| httpContext.Request.Headers.TryGetValue("X-Forwarded-Port", out StringValues fwdPortVal) && | ||
| int.TryParse(fwdPortVal.ToString(), out int fwdPort) && | ||
| fwdPort > 0) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I presume you're checking |
||
| { | ||
| return fwdPort; | ||
| } | ||
|
|
||
| // Infer scheme from context if available, else default to "http" | ||
| string scheme = httpContext?.Request.Scheme ?? "http"; | ||
|
|
||
| // Check ASPNETCORE_URLS env var | ||
| string? aspnetcoreUrls = Environment.GetEnvironmentVariable("ASPNETCORE_URLS"); | ||
|
|
||
| if (!string.IsNullOrWhiteSpace(aspnetcoreUrls)) | ||
| { | ||
| foreach (string part in aspnetcoreUrls.Split(new[] { ';', ',' }, StringSplitOptions.RemoveEmptyEntries)) | ||
| { | ||
| string trimmed = part.Trim(); | ||
|
|
||
| // Handle wildcard format (e.g. http://+:5002) | ||
| if (trimmed.StartsWith($"{scheme}://+:", StringComparison.OrdinalIgnoreCase)) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should we handle a weak wildcard format as well which uses https://learn.microsoft.com/en-us/windows/win32/http/urlprefix-strings likewise, would |
||
| { | ||
| int colonIndex = trimmed.LastIndexOf(':'); | ||
| if (colonIndex != -1 && | ||
| int.TryParse(trimmed.Substring(colonIndex + 1), out int wildcardPort) && | ||
| wildcardPort > 0) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. similar comment as above, should we also check the upper bound for valid ports? |
||
| { | ||
| return wildcardPort; | ||
| } | ||
| } | ||
|
|
||
| // Handle standard URI format | ||
| if (trimmed.StartsWith($"{scheme}://", StringComparison.OrdinalIgnoreCase) && | ||
| Uri.TryCreate(trimmed, UriKind.Absolute, out Uri? uri)) | ||
| { | ||
| return uri.Port; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| // Fallback | ||
| return scheme.Equals("https", StringComparison.OrdinalIgnoreCase) ? 443 : 5000; | ||
| } | ||
|
|
||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: for bool names try to use a prefix such as
issoisSelfSignedorisSelfSignEnabled, or something similar.