2

I've developed a gRPC service, on top of asp.net-core, testing it locally by hosting on Kestrel. In testing running on IIS, however, I have run into some oddities and discrepancies, which I was blaming on Microsoft. I have been trying to get IIS to replicate the behavior I saw when hosting in Kestrel.

One that I worked hard to replicate the Kestrel behavior with was including a trailer with key "www-authenticate", when authentication failed. IIS (but not Kestrel) throws an exception if you include this trailer, so I set out to get to the bottom of why, and whether I could prevent this exception, but still include the trailer.

Eventually I found the source code for where the exception was thrown here: https://github.com/dotnet/aspnetcore/blob/main/src/Shared/HttpSys/RequestProcessing/HeaderCollection.cs. It mentions an RFC, https://tools.ietf.org/html/rfc7230#section-4.1.2. That RFC specifically states that "A sender MUST NOT generate a trailer that contains" a whole set of fields, including those for authentication.

So, surprisingly enough, Microsoft looks to be in the right here, and IIS is right to disallow including the set of fields listed in HeaderCollection.cs as trailers.

But why does gRPC hosted elsewhere violate the standard in the RFC?

Shouldn't gRPC, wherever it is hosted, not include fields like this as trailers? Shouldn't they be sent as headers instead?

Edit to add code sample. All I had to do for this was put the following code into an rpc:

public override async Task<ProduceBadTrailerReply> ProduceBadTrailer(ProduceBadTrailerRequest request)
{
    var status = new Status(StatusCode.Unauthenticated, "throwing on purpose");
    var trailers = new Metadata() { new Metadata.Entry("www-authenticate", "auth failed on purpose") };
    await Task.CompletedTask;
    throw new RpcException(status, trailers);
}

With that code, running directly on Kestrel, I get 5 trailers: content-type, date, server, www-authenticate, and content-length.

rrreee
  • 753
  • 1
  • 6
  • 20
  • 1
    Sounds like a bug in Kestrel; do you have a minimal repro of Kestrel adding those trailers? – Marc Gravell Jul 27 '23 at 14:03
  • @MarcGravell , code sample added. What I'm still not clear on is what exactly gRPC is supposed to do. I understand that the server (whichever one) should disallow the trailers specified in the RFC. But I don't see why the gRPC layer would set them as trailers in the first place, if an RFC says not to. Should gRPC be setting these as headers? – rrreee Jul 28 '23 at 15:47
  • so: you're adding those trailers manually; all that is happening here is that the code is doing what you've asked it to, and nobody has added the "don't allow this, because reasons" check - to be fair, though, the person who should add that is probably: me! – Marc Gravell Jul 29 '23 at 14:30
  • Logged it: https://github.com/dotnet/aspnetcore/issues/49725 – Marc Gravell Jul 29 '23 at 14:37
  • Not quite. I'm adding it manually in my sample, yes, but only to demo the issue. If I get an authentication failure, via middleware (added by invoking AuthAppBuilderExtensions.UseAuthentication(this IApplicationBuilder app)), the middleware places this field in trailers. What I'm trying to understand is where this field, and those like it, properly belong. My aim is to make the output of my gRPC service identical, whether hosted on IIS or not, and the handling of trailers is not the same, so I've been adding interceptors to make it match, but I can't figure out what should be replicated. – rrreee Jul 31 '23 at 16:34

0 Answers0