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.