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

Subsequent Grpc calls with WinHttpHandler to an IIS hosted service fail #60291

Closed
angelyordanov opened this issue Oct 12, 2021 · 16 comments · Fixed by #62870
Closed

Subsequent Grpc calls with WinHttpHandler to an IIS hosted service fail #60291

angelyordanov opened this issue Oct 12, 2021 · 16 comments · Fixed by #62870
Assignees
Milestone

Comments

@angelyordanov
Copy link

angelyordanov commented Oct 12, 2021

Description

I'm trying to call a Grpc service hosted in IIS over http2 from NetFramework app. After reading the relevant docs(supported platforms) and issues (dotnet/aspnetcore#9020, dotnet/core#5713) I understand that this should be possible if I'm using Win11/WinServer2022 with the pre release version of the System.Net.Http.WinHttpHandler nuget package (in my case 6.0.0-rc.1.21451.13).

Unfortunately this seems not to be the case, as only the first call to the service succeeds and any subsequent call fails with Status(StatusCode="Cancelled", Detail="No grpc-status found on response. Using gRPC with WinHttp has Windows and package version requirements. See https://aka.ms/aspnet/grpc/netstandard for details.").

Things get even stranger when I tested combining calls made with the NetCore's SocketsHttpHandler. A call with the WinHttpHandler will fail no matter whether the first call to the service was made with WinHttp or Sockets, and it appears that the problem is somehow triggered by the state of the IIS application as restarting the host resets the issue(restarting the client has no effect). Furthermore even after the WinHttp call has failed one can successfully call the service with the Sockets handler from the same process.

Here is a table with the different setups

Client Server Result
WinHttp IIS ❌ Fail
WinHttp Kestrel ✔️ Succeeds
Sockets IIS ✔️ Succeeds
Sockets Kestrel ✔️ Succeeds

Reproduction Steps

I've created a minimal project that reproduces the problem - https://github.com/angelyordanov/grpc-iis-winhttp-sample

  1. Start the GrpcService with the IISExpress profile
  2. Start either one of the console apps

Expected behavior

There should be no exceptions and all grpc calls should succeed.

Actual behavior

The second call made with the WinHttpHandler always fails.

Regression?

No

Known Workarounds

No

Configuration

dotnet --info
.NET SDK (reflecting any global.json):
 Version:   5.0.401
 Commit:    4bef5f3dbf

Runtime Environment:
 OS Name:     Windows
 OS Version:  10.0.22000
 OS Platform: Windows
 RID:         win10-x64
 Base Path:   C:\Program Files\dotnet\sdk\5.0.401\

Other information

No response

@dotnet-issue-labeler dotnet-issue-labeler bot added area-System.Net.Http untriaged New issue has not been triaged by the area owner labels Oct 12, 2021
@ghost
Copy link

ghost commented Oct 12, 2021

Tagging subscribers to this area: @dotnet/ncl
See info in area-owners.md if you want to be subscribed.

Issue Details

Description

I'm trying to call a Grpc service hosted in IIS over http2 from NetFramework app. After reading the relevant docs(supported platforms) and issues (dotnet/aspnetcore#9020, dotnet/core#5713) I understand that this should be possible if I'm using Win11/WinServer2022 with the pre release version of the System.Net.Http.WinHttpHandler nuget package (in my case 6.0.0-rc.1.21451.13).

Unfortunately this seems not to be the case, as only the first call to the service succeeds and any subsequent call fails with Status(StatusCode="Cancelled", Detail="No grpc-status found on response. Using gRPC with WinHttp has Windows and package version requirements. See https://aka.ms/aspnet/grpc/netstandard for details.").

Things get even stranger when I tested combining calls made with the NetCore's SocketsHttpHandler. A call with the WinHttpHandler will fail no matter whether the first call to the service was made with WinHttp or Sockets, and it appears that the problem is somehow triggered by the state of the IIS application as restarting the host resets the issue(restarting the client has no effect).

Here is a table with the different setups

Client Server Result
WinHttp IIS ❌ Fail
WinHttp Kestrel ✔️ Succeeds
Sockets IIS ✔️ Succeeds
Sockets Kestrel ✔️ Succeeds

Reproduction Steps

I've created a minimal project that reproduces the problem - https://github.com/angelyordanov/grpc-iis-winhttp-sample

  1. Start the GrpcService with the IISExpress profile
  2. Start either one of the console apps

Expected behavior

There should be no exceptions and all grpc calls should succeed.

Actual behavior

The second call made with the WinHttpHandler always fails.

Regression?

No

Known Workarounds

No

Configuration

dotnet --info
.NET SDK (reflecting any global.json):
 Version:   5.0.401
 Commit:    4bef5f3dbf

Runtime Environment:
 OS Name:     Windows
 OS Version:  10.0.22000
 OS Platform: Windows
 RID:         win10-x64
 Base Path:   C:\Program Files\dotnet\sdk\5.0.401\

Other information

No response

Author: angelyordanov
Assignees: -
Labels:

area-System.Net.Http, untriaged

Milestone: -

@antonfirsov
Copy link
Member

This exception message is coming from grpc-dotnet, I recommend to open an issue on that repo, unless @JamesNK can confirm that this is something we should address in WinHttpHandler.

@JamesNK
Copy link
Member

JamesNK commented Oct 18, 2021

The error is coming from gRPC, but the reason it is throwing that error is that it can't find trailers on the HTTP response from WinHttpHandler.

It's really weird that this only happens when WinHttp is combined with IIS.

@JamesNK
Copy link
Member

JamesNK commented Oct 18, 2021

Here is SocketsHttpHandler calling IIS:

image

Trailer grpc-status is correctly set.

Here is WinHttpHandler calling IIS:

image

Trailer grpc-status is not set.

For sanity, here is WinHttpHandler calling Kestrel:

image

Trailer grpc-status is correctly set.

So there is something about WinHttpHandler + IIS + trailing headers that doesn't work.

IIS requires TLS for HTTP/2 so I can't get a Wireshark trace but I'm pretty sure the server will always be outputting trailing headers so it is likely an issue in WinHttpHandler.

All tests on .NET 6.

.NET SDK (reflecting any global.json):
 Version:   6.0.100-rtm.21504.5
 Commit:    457785c87e

@JamesNK
Copy link
Member

JamesNK commented Oct 18, 2021

I think there is a race condition here.

WinHttpHandler + IIS occasionally correctly loads the trailers. 90% of the time it fails. 10% of the time it works.

My theory is there is something about the shape of HTTP/2 frames that IIS returns compared to Kestrel.

@Tratcher
Copy link
Member

I wasn't able to repro this with IIS Express (VS 2022 RC) on Win11 22483.1011 & WinHttpHandler 6.0-rc2.

@karelz karelz added bug and removed untriaged New issue has not been triaged by the area owner labels Oct 26, 2021
@karelz karelz added this to the 7.0.0 milestone Oct 26, 2021
@antonfirsov
Copy link
Member

antonfirsov commented Dec 8, 2021

I'm can reproduce this with Win 11 22000.318 + VS 2019.

In the second call to the service GetResponseHeaderCharBufferLength returns 0, because the underlying WinHttp call returns 0 in bufferLengthInBytes:

bool result = Interop.WinHttp.WinHttpQueryHeaders(
requestHandle,
infoLevel,
Interop.WinHttp.WINHTTP_HEADER_NAME_BY_INDEX,
new IntPtr(buffer),
ref bufferLengthInBytes,
ref index);

This implies to me that WinHttp indeed thinks that there are no trailers in that response. Note that this happens comes consistently on the second call, I don't see how could there be a race condition.

Ideas:

  • Check VS2022 IIS Express in the same environment.
  • Update to a newer build of Win11 and/or ask the WinHttp team if they are aware of any recent WINHTTP_QUERY_FLAG_TRAILERS issue they fixed
  • Packet capture + decrypt TLS (never done this before but should be possible with WireShark AFAIK ...)

@JamesNK
Copy link
Member

JamesNK commented Dec 11, 2021

Issue is in WinHttpHandler.

WINHTTP_OPTION_REQUIRE_STREAM_END needs to be specified to instruct WinHttp to read all the way to the end of the response (e.g. trailing headers frame). Without this option then WinHttp stops once it has read up to content-length.

Issue shows up when WinHttpHandler is used with IIS because IIS sometimes includes content-length header with response.

@ghost ghost added the in-pr There is an active PR which will close this issue when it is merged label Dec 15, 2021
@ghost ghost removed the in-pr There is an active PR which will close this issue when it is merged label Dec 20, 2021
@antonfirsov
Copy link
Member

antonfirsov commented Dec 20, 2021

Reopening to track 6.0.x backport. This is a bug blocking .NET Framework gRPC developer workflow in Visual Studio + IIS Express.

@antonfirsov antonfirsov reopened this Dec 20, 2021
@antonfirsov antonfirsov modified the milestones: 7.0.0, 6.0.x Dec 20, 2021
@ghost ghost added in-pr There is an active PR which will close this issue when it is merged and removed in-pr There is an active PR which will close this issue when it is merged labels Jan 4, 2022
@antonfirsov
Copy link
Member

Backport PR is merged, this should be fixed with the upcoming (6.0.2 ?) update of the WinHttpHandler package.

@karelz
Copy link
Member

karelz commented Jan 11, 2022

Fixed in 7.0 (main) in PR #62870 and in 6.0.2 in PR #63346 6.0.4 in PR #63346 and #65523 (which is WinHttpHandler NuGet version 6.0.1 to make versioning even more confusing)

@angelyordanov
Copy link
Author

Now that .NET 6.0.2 is released shouldn't there be a 6.0.2 version for the System.Net.Http.WinHttpHandler nuget package with this fix included?

@JamesNK
Copy link
Member

JamesNK commented Feb 10, 2022

@karelz It doesn't appear that the NuGet - https://www.nuget.org/packages/System.Net.Http.WinHttpHandler/ - gets service releases. Is this expected? How should customers get this fix?

@karelz
Copy link
Member

karelz commented Feb 10, 2022

That is weird. @antonfirsov did we forget to update some package magic to get it released?

@antonfirsov
Copy link
Member

antonfirsov commented Feb 17, 2022

Apologies, looks like we didn't follow the nuget servicing guideline so it missed the release. I'm sorry for this. Working on it, so we don't miss the train. Reopening to track that work.

@antonfirsov antonfirsov reopened this Feb 17, 2022
@ghost ghost added the in-pr There is an active PR which will close this issue when it is merged label Feb 17, 2022
@ghost ghost removed the in-pr There is an active PR which will close this issue when it is merged label Mar 8, 2022
@karelz
Copy link
Member

karelz commented Mar 22, 2022

Fixed in 7.0 (main) in PR #62870 and in 6.0.2 in PR #63346 6.0.4 in PR #63346 and #65523 (which is WinHttpHandler NuGet version 6.0.1 to make versioning even more confusing)

@karelz karelz closed this as completed Mar 22, 2022
@ghost ghost locked as resolved and limited conversation to collaborators Apr 21, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants