Skip to content

Request timeouts are not applied without the middleware, no error given #52025

@Tratcher

Description

@Tratcher

Is there an existing issue for this?

  • I have searched the existing issues

Describe the bug

The request timeout feature relies on options, middleware, and attributes. If uses supply options or attributes, but forget the middleware, there's no indication that the timeouts aren't being applied.

Expected Behavior

Configuring timeouts on routes (or a default timeout policy ?) without adding the middleware should produce at least a runtime error rather than process the request without a timeout (dangerous). Note we also shouldn't short circuit endpoints with timeouts, we don't know what the short circuit logic is going to do.

An analyzer might help too.

We already have similar checks for auth, cors, and anti-forgery.

if (!_routeOptions.SuppressCheckForUnhandledSecurityMetadata)
{
if (endpoint.Metadata.GetMetadata<IAuthorizeData>() is not null)
{
ThrowCannotShortCircuitAnAuthRouteException(endpoint);
}
if (endpoint.Metadata.GetMetadata<ICorsMetadata>() is not null)
{
ThrowCannotShortCircuitACorsRouteException(endpoint);
}
if (endpoint.Metadata.GetMetadata<IAntiforgeryMetadata>() is { RequiresValidation: true } &&
httpContext.Request.Method is {} method &&
HttpExtensions.IsValidHttpMethodForForm(method))
{
ThrowCannotShortCircuitAnAntiforgeryRouteException(endpoint);
}

if (!_routeOptions.SuppressCheckForUnhandledSecurityMetadata)
{
if (endpoint.Metadata.GetMetadata<IAuthorizeData>() is not null &&
!httpContext.Items.ContainsKey(AuthorizationMiddlewareInvokedKey))
{
ThrowMissingAuthMiddlewareException(endpoint);
}
if (endpoint.Metadata.GetMetadata<ICorsMetadata>() is not null &&
!httpContext.Items.ContainsKey(CorsMiddlewareInvokedKey))
{
ThrowMissingCorsMiddlewareException(endpoint);
}
if (endpoint.Metadata.GetMetadata<IAntiforgeryMetadata>() is { RequiresValidation: true } &&
!httpContext.Items.ContainsKey(AntiforgeryMiddlewareWithEndpointInvokedKey))
{
ThrowMissingAntiforgeryMiddlewareException(endpoint);
}
}

Found when consuming this feature in YARP, and mitigated there: dotnet/yarp#2307

Steps To Reproduce

using Microsoft.AspNetCore.Http.Timeouts;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRequestTimeouts();

var app = builder.Build();
// app.UseRequestTimeouts(); // Woops, forgot this, nothing works.

app.MapGet("/", async (HttpContext context) => {
    try
    {
        await Task.Delay(TimeSpan.FromSeconds(10), context.RequestAborted);
    }
    catch (TaskCanceledException)
    {
        return Results.Content("Timeout!", "text/plain");
    }

    return Results.Content("No timeout!", "text/plain");
}).WithRequestTimeout(TimeSpan.FromSeconds(2));
// Returns "Timeout!"

app.MapGet("/attribute",
    [RequestTimeout(milliseconds: 2000)] async (HttpContext context) => {
        try
        {
            await Task.Delay(TimeSpan.FromSeconds(10), context.RequestAborted);
        }
        catch (TaskCanceledException)
        {
            return Results.Content("Timeout!", "text/plain");
        }

        return Results.Content("No timeout!", "text/plain");
    });
// Returns "Timeout!"

app.Run();

Exceptions (if any)

None (but there should be).

.NET Version

.NET 8

Anything else?

This enforcement pattern isn't scalable/extensible. 3rd parties can't use the Endpoint/RoutingMiddleware to do their own enforcement for the presence of middleware. And for us, if we keep adding checks it's going to get messy. Could this be abstracted to a service? What happens if the user then forgets to add the service?

Metadata

Metadata

Assignees

No one assigned

    Labels

    area-middlewareIncludes: URL rewrite, redirect, response cache/compression, session, and other general middlewaresarea-routing

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions