dotnet / aspnetcore

ASP.NET Core is a cross-platform .NET framework for building modern cloud-based web applications on Windows, Mac, or Linux.
https://asp.net
MIT License
35.19k stars 9.93k forks source link

Server header value customization #48798

Open marekott opened 1 year ago

marekott commented 1 year ago

Is there an existing issue for this?

Is your feature request related to a problem? Please describe the problem.

I have reverse proxy (asp net core app with Yarp) that is deployed in front of my microservices. When examining the response that was send to that proxy I would like to be able to determine if this is the response from mentioned proxy or microservice itself. Previously we have been using Kong which customized server header value so it was clear who responded to request. After switching to new solution both domain microservice and reverse proxy are responding with server header equal to "Kestrel".

Describe the solution you'd like

I would like to be able to customize server header value so it would be clear without any additional research who responded to incoming request. For example when request will be terminated by proxy due to fact that incoming request url doesn't match any of the yarp routes response header would look like this: image

I imagine it something like this:

.UseKestrel(o =>
{
    o.AddServerHeader = true;
    o.ServerHeaderValue = "MyServiceName";
})

Additional context

For now I believe I can achieve this with custom middleware but it would be great if this behavior would be achievable without such customization. It is important feature for my team since there are times during providing support for production incidents that we receive only screenshot from developer tools or xhr file and it would speed up determining logs of which component of our application we should examine (microservice and which one or reverse proxy).

amcasey commented 1 year ago

This feels related to #47408.

mitchdenny commented 1 year ago

I really think Middleware is the best way to do this rather than adding more behavior to Kestrel options. The benefit of having a pipeline which is extensible by middleware is to do exactly this kind of customization to responses. Your example usage doesn't seem to be more compact than just doing the following:

app.Use(async (context, next) =>
{
    context.Response.Headers["Server"] = "MyServiceName";
    await next(context);
});
marekott commented 1 year ago

Hi @mitchdenny, thanks for your feedback. My case would rather be like this:

await _next(context);

if (!context.Response.Headers.ContainsKey("Server"))
{
    context.Response.Headers["Server"] = "MyServiceName";
}

Since if the request was forwarded I want to respect Server header added by domain microservice. I understand your point but let me share my thoughts:

  1. There is a possibility that request will be terminated before reaching my middleware and above logic will not execute.
  2. The fact that every time someone will need to implement it by himself is not a perfect solution since it can lead to not obvious bugs due to wrong middleware registration order for example.

Btw, which component is setting server header when it is enabled? MVC, server itself?

ghost commented 1 year ago

We've moved this issue to the Backlog milestone. This means that it is not going to be worked on for the coming release. We will reassess the backlog following the current release and consider this item at that time. To learn more about our issue management process and to have better expectation regarding different types of issues you can read our Triage Process.

mitchdenny commented 1 year ago

If your goal is to just differentiate proxied requests vs. requests that came from the proxy itself you could remove the header from the non-proxied requests with something like this:

builder.WebHost.ConfigureKestrel(options =>
{
    options.AddServerHeader = false;
});

In this case requests that are non-proxied won't have a server header, and ones that are will just pass along what the downstream server sent.

Note, one of the objections raised to using middleware for this was that using middleware could result in the logic not getting executed. Assuming you set your middleware early in the pipeline this shouldn't happen unless the connection is severed - at which point setting the server header is moot :)

As for where the default header is being set, that is in the HttpProtocol implementation in Kestrel:

https://source.dot.net/#Microsoft.AspNetCore.Server.Kestrel.Core/Internal/Http/HttpProtocol.cs,1242

At this point I think my recommendation of using middleware for this stands but I'll put this on the backlog just in case we get more folks who think we need an API especially for this.

KrzysztofBranicki commented 1 year ago

Hi, my use case is that with the following setup Load balancer -> ApiGateway (ASP YARP) -> bunch of microservices (ASP) I want to be able to know which tier terminated the request just by inspecting the server header. So server header should contain either the name of the microservice or ApiGateway or name of other infrastructure component that is in front of ApiGateway e.g. load balancer. Currently it is cumbersome because you need to set the header early in processing pipeline but if you are using YARP then you need to also replace it with the header returned from the forwarder. You need to make sure as well that proper middleware is used in tens of microservices and that in non of those microservices someone defined middleware before middleware which is setting server header (risk of terminating request before setting it). Long story short it would be rely useful to have a feature where we would to be able to configure arbitrary name for the server.