From 47d682b8cf3fe811d787ec51e683f7211ce49691 Mon Sep 17 00:00:00 2001 From: Andrew Butler <1628649+AButler@users.noreply.github.com> Date: Thu, 12 Oct 2023 10:43:04 +0100 Subject: [PATCH] Add Azure App Services middleware --- LogOtter.sln | 6 +++++ sample/CustomerApi/CustomerApi.csproj | 1 + sample/CustomerApi/Program.cs | 2 ++ .../ConfigureExtensions.cs | 14 +++++++++++ ...Azure.AppServices.RequestMiddleware.csproj | 21 ++++++++++++++++ .../README.md | 17 +++++++++++++ .../RestoreRawRequestPathMiddleware.cs | 25 +++++++++++++++++++ src/LogOtter.Hub/LogOtter.Hub.csproj | 2 ++ src/LogOtter.Hub/Program.cs | 2 ++ 9 files changed, 90 insertions(+) create mode 100644 src/LogOtter.Azure.AppServices.RequestMiddleware/ConfigureExtensions.cs create mode 100644 src/LogOtter.Azure.AppServices.RequestMiddleware/LogOtter.Azure.AppServices.RequestMiddleware.csproj create mode 100644 src/LogOtter.Azure.AppServices.RequestMiddleware/README.md create mode 100644 src/LogOtter.Azure.AppServices.RequestMiddleware/RestoreRawRequestPathMiddleware.cs diff --git a/LogOtter.sln b/LogOtter.sln index 8494f623..f2880cb4 100644 --- a/LogOtter.sln +++ b/LogOtter.sln @@ -44,6 +44,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CustomerWorker", "sample\Cu EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LogOtter.Hub", "src\LogOtter.Hub\LogOtter.Hub.csproj", "{1DEBB304-17E4-4FAE-9772-3B3CC6DF8EEF}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LogOtter.Azure.AppServices.RequestMiddleware", "src\LogOtter.Azure.AppServices.RequestMiddleware\LogOtter.Azure.AppServices.RequestMiddleware.csproj", "{A644FC0B-D646-49EB-91A1-0AC9CB719C74}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -130,6 +132,10 @@ Global {1DEBB304-17E4-4FAE-9772-3B3CC6DF8EEF}.Debug|Any CPU.Build.0 = Debug|Any CPU {1DEBB304-17E4-4FAE-9772-3B3CC6DF8EEF}.Release|Any CPU.ActiveCfg = Release|Any CPU {1DEBB304-17E4-4FAE-9772-3B3CC6DF8EEF}.Release|Any CPU.Build.0 = Release|Any CPU + {A644FC0B-D646-49EB-91A1-0AC9CB719C74}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A644FC0B-D646-49EB-91A1-0AC9CB719C74}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A644FC0B-D646-49EB-91A1-0AC9CB719C74}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A644FC0B-D646-49EB-91A1-0AC9CB719C74}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(NestedProjects) = preSolution {5E67A3CB-9089-4AA1-802C-B8CF9DFEEF58} = {3013166D-3A9F-4979-B741-08D4288F5D28} diff --git a/sample/CustomerApi/CustomerApi.csproj b/sample/CustomerApi/CustomerApi.csproj index c0b54a6d..043069da 100644 --- a/sample/CustomerApi/CustomerApi.csproj +++ b/sample/CustomerApi/CustomerApi.csproj @@ -18,6 +18,7 @@ + diff --git a/sample/CustomerApi/Program.cs b/sample/CustomerApi/Program.cs index d329186b..ecdb713e 100644 --- a/sample/CustomerApi/Program.cs +++ b/sample/CustomerApi/Program.cs @@ -5,6 +5,7 @@ using CustomerApi.HealthChecks; using CustomerApi.NonEventSourcedData.CustomerInterests; using CustomerApi.Services; +using LogOtter.Azure.AppServices.RequestMiddleware; using LogOtter.CosmosDb; using LogOtter.CosmosDb.EventStore; using LogOtter.CosmosDb.EventStore.EventStreamApi; @@ -84,6 +85,7 @@ var app = builder.Build(); +app.UseRestoreRawRequestPathMiddleware(); app.UseCors(); if (app.Environment.IsDevelopment()) diff --git a/src/LogOtter.Azure.AppServices.RequestMiddleware/ConfigureExtensions.cs b/src/LogOtter.Azure.AppServices.RequestMiddleware/ConfigureExtensions.cs new file mode 100644 index 00000000..a34a9c2d --- /dev/null +++ b/src/LogOtter.Azure.AppServices.RequestMiddleware/ConfigureExtensions.cs @@ -0,0 +1,14 @@ +using Microsoft.AspNetCore.Builder; + +namespace LogOtter.Azure.AppServices.RequestMiddleware; + +public static class ConfigureExtensions +{ + public static WebApplication UseRestoreRawRequestPathMiddleware(this WebApplication webApplication) + { + webApplication.UseMiddleware(); + webApplication.UseRouting(); + + return webApplication; + } +} diff --git a/src/LogOtter.Azure.AppServices.RequestMiddleware/LogOtter.Azure.AppServices.RequestMiddleware.csproj b/src/LogOtter.Azure.AppServices.RequestMiddleware/LogOtter.Azure.AppServices.RequestMiddleware.csproj new file mode 100644 index 00000000..c029ff3e --- /dev/null +++ b/src/LogOtter.Azure.AppServices.RequestMiddleware/LogOtter.Azure.AppServices.RequestMiddleware.csproj @@ -0,0 +1,21 @@ + + + + net7.0 + enable + enable + LogOtter.Azure.AppServices.RequestMiddleware + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + diff --git a/src/LogOtter.Azure.AppServices.RequestMiddleware/README.md b/src/LogOtter.Azure.AppServices.RequestMiddleware/README.md new file mode 100644 index 00000000..29b8e4c7 --- /dev/null +++ b/src/LogOtter.Azure.AppServices.RequestMiddleware/README.md @@ -0,0 +1,17 @@ +> ⚠️ Warning: LogOtter is still in beta and there are likely to be breaking changes prior to a v1 release. Use at your own peril! + +# Azure AppServices RequestMiddleware + +Adds middleware for converting the request back to the original request (Azure AppServices +decode path strings and there is currently no way to disable). + +For more information see [dotnet/aspnetcore#40532](https://github.com/dotnet/aspnetcore/issues/40532) +and [Azure/azure-functions-host#9402](https://github.com/Azure/azure-functions-host/pull/9402#issuecomment-1747347531) + +## Examples + +Register the middleware + +```c# +app.UseRestoreRawRequestPathMiddleware(); +``` diff --git a/src/LogOtter.Azure.AppServices.RequestMiddleware/RestoreRawRequestPathMiddleware.cs b/src/LogOtter.Azure.AppServices.RequestMiddleware/RestoreRawRequestPathMiddleware.cs new file mode 100644 index 00000000..2291f6e3 --- /dev/null +++ b/src/LogOtter.Azure.AppServices.RequestMiddleware/RestoreRawRequestPathMiddleware.cs @@ -0,0 +1,25 @@ +using Microsoft.AspNetCore.Http; + +namespace LogOtter.Azure.AppServices.RequestMiddleware; + +public class RestoreRawRequestPathMiddleware +{ + private const string UnencodedUrlHeaderName = "X-Waws-Unencoded-Url"; + + private readonly RequestDelegate _next; + + public RestoreRawRequestPathMiddleware(RequestDelegate next) + { + _next = next; + } + + public async Task Invoke(HttpContext context) + { + if (context.Request.Headers.TryGetValue(UnencodedUrlHeaderName, out var unencodedUrlValue) && unencodedUrlValue.Any()) + { + context.Request.Path = new PathString(unencodedUrlValue.First()); + } + + await _next(context); + } +} diff --git a/src/LogOtter.Hub/LogOtter.Hub.csproj b/src/LogOtter.Hub/LogOtter.Hub.csproj index 2913d422..94a8533a 100644 --- a/src/LogOtter.Hub/LogOtter.Hub.csproj +++ b/src/LogOtter.Hub/LogOtter.Hub.csproj @@ -5,9 +5,11 @@ enable enable Linux + false + diff --git a/src/LogOtter.Hub/Program.cs b/src/LogOtter.Hub/Program.cs index f4b6547c..de5ba57d 100644 --- a/src/LogOtter.Hub/Program.cs +++ b/src/LogOtter.Hub/Program.cs @@ -1,3 +1,4 @@ +using LogOtter.Azure.AppServices.RequestMiddleware; using LogOtter.Hub.Configuration; using LogOtter.Hub.Services; @@ -22,6 +23,7 @@ app.ConfigureReverseProxy(serviceOptions); +app.UseRestoreRawRequestPathMiddleware(); app.UseCors(); app.UseFileServer(); app.UseRouting();