From 96934b682485fcd47d9851f7ebeacc59aaa650a0 Mon Sep 17 00:00:00 2001 From: Fritiof Hedman Date: Sun, 7 Jun 2026 20:19:35 +0200 Subject: [PATCH] Add support for forwarding headers --- src/FrameProcessor/Program.cs | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/FrameProcessor/Program.cs b/src/FrameProcessor/Program.cs index 995c308..85b9963 100644 --- a/src/FrameProcessor/Program.cs +++ b/src/FrameProcessor/Program.cs @@ -1,3 +1,4 @@ +using System.Net; using FrameProcessor.Concurrency; using FrameProcessor.Configuration; using FrameProcessor.ImagePipeline; @@ -5,10 +6,13 @@ using FrameProcessor.Middleware; using FrameProcessor.Mqtt; using FrameProcessor.Storage; using FrameProcessor.UrlFetch; +using Microsoft.AspNetCore.HttpOverrides; using Microsoft.AspNetCore.Mvc.ModelBinding; using Microsoft.Extensions.Options; using Microsoft.OpenApi; using Serilog; +using AspForwardedHeadersOptions = Microsoft.AspNetCore.Builder.ForwardedHeadersOptions; +using ForwardedHeadersOptions = FrameProcessor.Configuration.ForwardedHeadersOptions; var builder = WebApplication.CreateBuilder(args); @@ -135,6 +139,9 @@ builder.Services.AddOptions() .ValidateDataAnnotations() .ValidateOnStart(); +builder.Services.AddOptions() + .Bind(builder.Configuration.GetSection(ForwardedHeadersOptions.SectionName)); + // FramesOptions is bound but not validated via the options pipeline so that // IOptionsMonitor can fire OnChange with invalid content during // hot-reload without throwing. FramesRegistry takes responsibility for both @@ -169,6 +176,25 @@ var app = builder.Build(); // Eagerly resolve FramesRegistry so an invalid frames.json fails startup fast. _ = app.Services.GetRequiredService(); +// Honor X-Forwarded-Proto/Host from the reverse proxy so generated URLs +// (OpenAPI, Swagger UI) use the externally-visible scheme and host. +var proxyConfig = app.Services.GetRequiredService>().Value; +var forwardedHeadersOptions = new AspForwardedHeadersOptions +{ + ForwardedHeaders = ForwardedHeaders.XForwardedProto | ForwardedHeaders.XForwardedHost, +}; +forwardedHeadersOptions.KnownIPNetworks.Clear(); +forwardedHeadersOptions.KnownProxies.Clear(); +foreach (var network in proxyConfig.KnownNetworks) +{ + forwardedHeadersOptions.KnownIPNetworks.Add(System.Net.IPNetwork.Parse(network)); +} +foreach (var proxy in proxyConfig.KnownProxies) +{ + forwardedHeadersOptions.KnownProxies.Add(IPAddress.Parse(proxy)); +} +app.UseForwardedHeaders(forwardedHeadersOptions); + app.MapOpenApi(); app.UseSwaggerUI(options => {