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

Fix TestServer from blocking on request stream #15591

Merged
merged 4 commits into from
Oct 31, 2019

Conversation

JamesNK
Copy link
Member

@JamesNK JamesNK commented Oct 27, 2019

Fixes #15415

HttpContent.ReadAsStreamAsync() will block when called in custom HttpContent implementations. Calling HttpContent.CopyToAsync(stream) mirrors what HttpClient does more closely.

Note, this PR is on 3.1. The bug blocks people from using TestServer with gRPC. Would be nice to unblock before 5.0. @anurse is this your call? Need anymore info?

@davidfowl
Copy link
Member

Do it in 5.0 then backport to 3.1?

@Tratcher
Copy link
Member

HttpContent.ReadAsStreamAsync() will block when called in custom HttpContent implementations.

Which custom HttpContent implementations? It sounds like the content objects are at fault here. I'm not sure why you're changing the server to accommodate them.

@Tratcher
Copy link
Member

Do it in 5.0 then backport to 3.1?

Forward is easier than backwards.

@davidfowl
Copy link
Member

Which custom HttpContent implementations? It sounds like the content objects are at fault here. I'm not sure why you're changing the server to accommodate them.

Sorta but not really. It's much more complicated to implement this in each HttpContent. See https://github.com/dotnet/corefx/blob/26d7b6626ab0385a1158e674855f81ab73f628e0/src/System.Net.Http/src/System/Net/Http/HttpContent.cs#L453

I had the same impression at first but it's far easier to make this work in TestServer than it is to fix the HttpContent implementation (just like we auto-rewind your Stream, though I don't, agree with that one).

Forward is easier than backwards.

But then we can't merge it until it goes through the layers of approval. But whatever works I guess.

@JamesNK
Copy link
Member Author

JamesNK commented Oct 27, 2019

Which custom HttpContent implementations?

https://github.com/grpc/grpc-dotnet/blob/9e39edb0a3fc7a625085490bf64c2794870a519e/src/Grpc.Net.Client/Internal/PushStreamContent.cs

It sounds like the content objects are at fault here. I'm not sure why you're changing the server to accommodate them.

No TestServer is at fault for using HttpContent.ReadAsStreamAsync instead of HttpContent.CopyToAsync. HttpContent.ReadAsStreamAsync is never called on the request content by HttpClientHandler.

Should the gRPC content fix itself so ReadAsStreamAsync is supported without blocking? Maybe. But that's a separate issue.

@JamesNK
Copy link
Member Author

JamesNK commented Oct 27, 2019

Related question in HttpClient-side - https://github.com/dotnet/corefx/issues/42160

@Tratcher
Copy link
Member

No TestServer is at fault for using HttpContent.ReadAsStreamAsync instead of HttpContent.CopyToAsync. HttpContent.ReadAsStreamAsync is never called on the request content by HttpClientHandler.

Should the gRPC content fix itself so ReadAsStreamAsync is supported without blocking? Maybe. But that's a separate issue.

Content that expect to stream really should implement CreateContentReadStreamAsync and then you wouldn't have to change anything in TestServer, no?

@davidfowl
Copy link
Member

This change to TestServer is fine

@JamesNK
Copy link
Member Author

JamesNK commented Oct 28, 2019

/cc @Pilchie / @anurse for 3.1.0-preview3 consideration

@JamesNK
Copy link
Member Author

JamesNK commented Oct 29, 2019

Also, looking for review approvals // @davidfowl, @Tratcher

@analogrelay
Copy link
Contributor

TestServer is a pretty low-risk area. I'm in favor for 3.1. It's @Pilchie 's final call though.

src/Hosting/TestHost/src/ClientHandler.cs Outdated Show resolved Hide resolved
src/Hosting/TestHost/src/ClientHandler.cs Outdated Show resolved Hide resolved
src/Hosting/TestHost/src/HttpContextBuilder.cs Outdated Show resolved Hide resolved
src/Hosting/TestHost/src/ClientHandler.cs Outdated Show resolved Hide resolved
@JamesNK JamesNK force-pushed the jamesnk/testserver-clientstreaming branch from b4a7f55 to 2ee8f82 Compare October 29, 2019 22:17
@JamesNK
Copy link
Member Author

JamesNK commented Oct 29, 2019

🆙 📅

src/Hosting/TestHost/src/HttpContextBuilder.cs Outdated Show resolved Hide resolved
src/Hosting/TestHost/test/TestClientTests.cs Outdated Show resolved Hide resolved
src/Hosting/TestHost/test/TestClientTests.cs Outdated Show resolved Hide resolved
@Pilchie
Copy link
Member

Pilchie commented Oct 29, 2019

What is the scenario for TestHost is it (as the name implies) purely for testing, or is it something that customers use on a regular basis in production that we could break?

@analogrelay
Copy link
Contributor

analogrelay commented Oct 30, 2019

What is the scenario for TestHost is it (as the name implies) purely for testing, or is it something that customers use on a regular basis in production that we could break?

It's for testing only. Using it in a production is not supported. It doesn't ship in any shared framework.

Essentially it's an in-memory test server. You can point it at your app setup (middlewares, services, etc.) and it will start up a fake "app" and give you an HttpClient that can make fake "requests" to your app.

@davidfowl
Copy link
Member

What is the scenario for TestHost is it (as the name implies) purely for testing, or is it something that customers use on a regular basis in production that we could break?

People use it in Azure functions to bootstrap ASP.NET Core on top of Azure functions.

src/Hosting/TestHost/src/HttpContextBuilder.cs Outdated Show resolved Hide resolved
configureContext(_httpContext, _requestPipe.Reader);
}

internal void SendRequestStream(Func<PipeWriter, Task> sendRequestStream)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The layering still seems odd here. Only ClientHandler needs/uses the request body pipe and _sendRequestStreamTask, why doesn't it own those? What it needs from HttpContextBuilder is a callback for CompleteRequestAsync and/or cancel.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did it this way because the alternative is callbacks everywhere:

  1. After request is complete
  2. Request is aborted from server
  3. Request is aborted from client

Sure HttpContextBuilder owns the request pipe and task, but using it is optional.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea I don’t think this layering is super important

@Pilchie
Copy link
Member

Pilchie commented Oct 30, 2019

Ok, Approved for 3.1.0-Preview3.

@JamesNK
Copy link
Member Author

JamesNK commented Oct 31, 2019

Is there any more feedback/changes required here?

@JamesNK JamesNK merged commit cfea2e9 into release/3.1 Oct 31, 2019
@JamesNK JamesNK deleted the jamesnk/testserver-clientstreaming branch October 31, 2019 21:48
@JamesNK JamesNK added this to the 3.1.0-preview3 milestone Nov 3, 2019
@amcasey amcasey added area-networking Includes servers, yarp, json patch, bedrock, websockets, http client factory, and http abstractions and removed area-runtime labels Aug 24, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-networking Includes servers, yarp, json patch, bedrock, websockets, http client factory, and http abstractions
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants