Skip to content
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

Updating HttpContext.Request.Path inside middleware has no effect in selecting the endpoint for the request #49454

Closed
1 task done
kshyju opened this issue Jul 17, 2023 · 3 comments
Labels
area-networking Includes servers, yarp, json patch, bedrock, websockets, http client factory, and http abstractions ✔️ Resolution: Answered Resolved because the question asked by the original author has been answered. Status: Resolved

Comments

@kshyju
Copy link

kshyju commented Jul 17, 2023

Is there an existing issue for this?

  • I have searched the existing issues

Describe the bug

As mentioned in issues such as this and this, Azure app service FE/proxy decodes the encoded parts of the request URL path. The recommendation is to use the X-WAWS-Unencoded-URL header value to get the un decoded/raw value.

What is the right extensibility point in aspnet core pipeline to replace the current request path string value to the value of the above mentioned header, so that the routing module uses it and route it to the correct endpoint? The use case here is having a route parameter for which the value contains %2F (encoded version of /) in it.

[HttpGet]
[Route("api/departments/{dept}")]
public IActionResult Get(string dept)
{
    _logger.LogInformation($"Request received for dept:{dept}");

    return new OkObjectResult($"Param dept:{dept}");
}

and a request like this api/departments/cloud%2Fdevdiv

This code works fine locally, but fails when deployed to app service.

I wrote a middleware which replaces the request path of httpcontext and registered as the very first middleware in the request processing pipeline, but that does not seems to work.

public async Task InvokeAsync(HttpContext context)
{
    if (context.Request.Headers.TryGetValue("X-Waws-Unencoded-Url", out var unencodedUrlValue))
    {
        _logger.LogInformation($"X-Waws-Unencoded-Url header value: {unencodedUrlValue.First()}");
        context.Request.Path = unencodedUrlValue.First();
    }

    // Call the next delegate/middleware in the pipeline.
    await _next(context);
}

and

public static void Main(string[] args)
{
    var builder = WebApplication.CreateBuilder(args);
    builder.Services.AddControllers();
    var app = builder.Build();

    app.UseMiddleware<RequestPathCheckMiddleware>();
   // other middlewares are registered here.

    app.MapControllers();
    app.Run();
}

Is this not the right extensibility point to make this change?

AI logs of 2 requests, one resulted in 200 OK and the other is 404

image

Expected Behavior

Should be able to replace the request path value with the raw value received from header and the routing/endpoint selection should respect that during the same request processing. Not looking to return a redirect response.

Steps To Reproduce

Code shared in he issue description is enough to repro. To validate locally, you may also try to replace the path value with the route to a different endpoint like below.

app.Use(async (context, next) =>
{
    var url = context.Request.Path.Value;
    if (url.Contains("/api/products"))
    {
        context.Request.Path = "/api/tags";
    }

    await next();
});

Here, the expected behavior is that, the /api/products request to be invoking the code from the endpoint with /api/tags route decoration.

Exceptions (if any)

No response

.NET Version

net6.0

Anything else?

No response

@davidfowl
Copy link
Member

It can but you have to add the UseRouting middleware after you change the path in your middleware

@kshyju
Copy link
Author

kshyju commented Jul 17, 2023

Thank you! Calling UseRouting seems to do the trick. Below is the working version of code for anyone interested.

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();

var app = builder.Build();

app.UseMiddleware<RequestPathCheckMiddleware>();
app.UseRouting();
app.UseEndpoints(endpoints => endpoints.MapControllers());

app.Run();

@Tratcher Tratcher added the ✔️ Resolution: Answered Resolved because the question asked by the original author has been answered. label Jul 17, 2023
@ghost ghost added the Status: Resolved label Jul 17, 2023
@ghost
Copy link

ghost commented Jul 19, 2023

This issue has been resolved and has not had any activity for 1 day. It will be closed for housekeeping purposes.

See our Issue Management Policies for more information.

@ghost ghost closed this as completed Jul 19, 2023
@ghost ghost locked as resolved and limited conversation to collaborators Aug 18, 2023
@amcasey amcasey added area-networking Includes servers, yarp, json patch, bedrock, websockets, http client factory, and http abstractions and removed area-runtime labels Aug 25, 2023
This issue was closed.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-networking Includes servers, yarp, json patch, bedrock, websockets, http client factory, and http abstractions ✔️ Resolution: Answered Resolved because the question asked by the original author has been answered. Status: Resolved
Projects
None yet
Development

No branches or pull requests

5 participants
@davidfowl @kshyju @Tratcher @amcasey and others