mirror of
https://github.com/okieselbach/AutopilotMonitor.git
synced 2026-10-26 21:47:13 +00:00
22427e24c5
Post-deploy re-validation in the browser surfaced two issues that the previous commit did not actually solve: - Timing-Allow-Origin was still missing on every API response (curl confirmed) and X-Correlation-ID was missing too — a preexisting bug. Both middlewares used httpContext.Response.OnStarting() to attach the header, but that callback is not reliably triggered in the .NET 8 isolated worker: the host bridges the worker's response to the wire, so OnStarting fires on a shadow object that never reaches the client. UserRateLimitMiddleware already writes X-RateLimit-* directly on Response.Headers before calling next(), and those headers do come through in production. Switching both header-emitting middlewares to that pattern. - /dashboard kept firing /api/config/<t>/feature-flags twice. The earlier dep-stabilization on useTenantSecurityConfig was incomplete: the effect fires once on initial render with user=null (deps [tenantId, undefined, undefined, undefined]) and once after AuthContext resolves user (deps [tenantId, bool, bool, role]) — two distinct dep tuples, two fetches. The user=null path also bypassed the role gate (the guard was `if (user && ...) return`). Adding `!user` to the early-return at the top of the effect collapses to one fetch and also drops the would-be 401 we were producing during the loading window. Backend tests 1058/1058, web vitest 249/249, tsc clean. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
36 lines
1.5 KiB
C#
36 lines
1.5 KiB
C#
using Microsoft.Azure.Functions.Worker;
|
|
using Microsoft.Azure.Functions.Worker.Middleware;
|
|
|
|
namespace AutopilotMonitor.Functions.Middleware;
|
|
|
|
/// <summary>
|
|
/// Adds the <c>Timing-Allow-Origin: *</c> response header so cross-origin
|
|
/// callers (notably the portal) can read full Resource Timing details
|
|
/// (<c>transferSize</c>, <c>encodedBodySize</c>, <c>nextHopProtocol</c>, ...)
|
|
/// from the browser's <c>performance.getEntriesByType('resource')</c>.
|
|
/// Without this header those fields stay zero / "unknown" and our own
|
|
/// real-user monitoring cannot see API payload sizes.
|
|
/// </summary>
|
|
public class TimingAllowOriginMiddleware : IFunctionsWorkerMiddleware
|
|
{
|
|
private const string HeaderName = "Timing-Allow-Origin";
|
|
private const string HeaderValue = "*";
|
|
|
|
public async Task Invoke(FunctionContext context, FunctionExecutionDelegate next)
|
|
{
|
|
// Write directly on Response.Headers before next() — the
|
|
// OnStarting() callback is not reliably triggered in the .NET 8
|
|
// isolated worker (the host bridges the worker's response, so the
|
|
// hook fires on a shadow object that never reaches the wire). The
|
|
// direct-write pattern is the same one UserRateLimitMiddleware uses
|
|
// for X-RateLimit-* and is observed in production responses.
|
|
var httpContext = context.GetHttpContext();
|
|
if (httpContext != null && !httpContext.Response.Headers.ContainsKey(HeaderName))
|
|
{
|
|
httpContext.Response.Headers[HeaderName] = HeaderValue;
|
|
}
|
|
|
|
await next(context);
|
|
}
|
|
}
|