Windows Server Insiders getting gRPC support in Http.sys

We keep hearing many of you are eager to host gRPC-enabled services on IIS in Azure, such as here on GitHub. However, the lack of support for several HTTP features in the platform components is blocking you. We listened, and we have good news: we built HTTP support for gRPC into Http.sys! We are targeting the feature for vNext. You can try it out today if you have access to Insider builds.

Let us back up a bit. gRPC is a “modern open-source high-performance RPC framework”. You can read more about it here on the gRPC website. It allows clients and backends to communicate with one another with relative ease while using different frameworks and languages. In theory, such communication is achievable with JSON serialization. However, gRPC significantly outperforms it in terms of message sizes and speed of serialization. For its full functionality, it has more requirements from the implementation of the HTTP/2 protocol, which is the transport for gRPC. Unlike the browser scenarios, it requires support for bidirectional streaming and response trailers. Http.sys has always supported bidirectional streaming, but the response trailers were a feature gap up to this point. You can read more about the use of gRPC here in the context of .NET and usage patterns.

If you want to try out native gRPC support in Http.sys, you will need to start by getting an Insider build of . You can do that by following the instructions on the Windows Server Insider Preview page.

Once you have your Windows Server vNext installed, you can test out the new HTTP features, whether you are building on top of Http.sys or simply want to see it working under the hood. The following code sample will show you verify the necessary HTTP features are working properly.

PSTR ResponseBody = “Response Body”;
HTTP_CACHE_POLICY CachePolicy = {0};

Trailers[0].pName = “Trailer1”;
Trailers[0].NameLength = (USHORT)strlen(Trailer[0].pName);
Trailers[0].pRawValue = “Value1”;
Trailers[0].RawValueLength = (USHORT)strlen(Trailer[0].pRawValue);

Trailers[1].pName = “Trailer2”;
Trailers[1].NameLength = (USHORT)strlen(Trailer[0].pName);
Trailers[1].pRawValue = “Value2”;
Trailers[1].RawValueLength = (USHORT)strlen(Trailer[0].pRawValue);

Chunks[0].DataChunkType = HttpDataChunkFromMemory;
Chunks[0].FromMemory.pBuffer = (PVOID)ResponseBody;
Chunks[0].FromMemory.BufferLength = (USHORT)strlen(ResponseBody);

Chunks[1].DataChunkType = HttpDataChunkTrailers;
Chunks[1].Trailers.TrailerCount = RTL_NUMBER_OF(Trailers);
Chunks[1].Trailers.pTrailers = Trailers;

RtlZeroMemory(&Response, sizeof(Response));

Response.StatusCode = 200;
Response.pReason = “OK”;
Response.ReasonLength = (USHORT) strlen(Response.pReason);

Response.pEntityChunks = Chunks;
Response.EntityChunkCount = RTL_NUMBER_OF(Chunks);

Error = HttpSendHttpResponse(RequestQueue,

We are excited about this feature and eager to hear you feedback!


This article was originally published by Microsoft's Azure Blog. You can find the original article here.