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

Override ReadToEndAsync in HttpRequestStreamReader #13834

Closed
davidfowl opened this issue Sep 9, 2019 · 11 comments
Closed

Override ReadToEndAsync in HttpRequestStreamReader #13834

davidfowl opened this issue Sep 9, 2019 · 11 comments
Labels
area-networking Includes servers, yarp, json patch, bedrock, websockets, http client factory, and http abstractions good first issue Good for newcomers. help wanted Up for grabs. We would accept a PR to help resolve this issue
Milestone

Comments

@davidfowl
Copy link
Member

#4707 (comment)

When doing using HttpRequestStreamReader.ReadToEndAsync it's possible to end up doing blocking reads since we don't override ReadAsync(Memory<char>)

@mkArtakMSFT mkArtakMSFT added the feature-platform Deprecated: Cross-cutting issues related to ASP.NET Core as a platform label Sep 10, 2019
@analogrelay analogrelay added area-servers and removed feature-platform Deprecated: Cross-cutting issues related to ASP.NET Core as a platform labels Oct 8, 2019
@analogrelay
Copy link
Contributor

We actually need to directly override ReadToEndAsync since it just Task.Runs ReadToEnd(): https://source.dot.net/#q=TextReader.ReadToEndAsync

@analogrelay analogrelay changed the title Override ReadAsync(Memory<char>) in HttpRequestStreamReader Override ReadToEndAsync in HttpRequestStreamReader Oct 8, 2019
@analogrelay analogrelay self-assigned this Oct 8, 2019
@analogrelay analogrelay added this to the 5.0.0-preview1 milestone Oct 8, 2019
@rgueldenpfennig
Copy link

I'm a bit surprised that this bug is planned to be fixed in the 5.0.0 milestone. Due to #7644 we changed our code from

using (var reader = new HttpRequestStreamReader(context.Request.Body, encoding: Encoding.UTF8))
var body = await reader.ReadToEndAsync();

to

using (var reader = new StreamReader(context.Request.Body, Encoding.UTF8, leaveOpen: true))
var body = await reader.ReadToEndAsync();

To prevent IO from blocking.

Is this a recommended workaround?

@thomaslevesque
Copy link
Member

That's really bad... Definitely a bug. Any chance it could be fixed earlier than 5.0.0? I'm willing to submit a PR for this.

@analogrelay
Copy link
Contributor

Apologies for the delay in response, this fell off my radar a bit and then the holidays hit :).

Is this a recommended workaround?

@rgueldenpfennig Yes, that would be the recommended workaround.

Any chance it could be fixed earlier than 5.0.0? I'm willing to submit a PR for this.

@thomaslevesque In general, we are very conservative about what we fix in patch releases (3.1.x). That doesn't mean we wouldn't do it, but it's a decision that's made at a higher level (coordinated with all the other parts of .NET Core) ;). If you're still interested in sending a PR, I'd suggest submitting one to make the fix in master. We can open a new issue to track a request to backport the change to the next 3.1.x patch and submit that for servicing approval.

@thomaslevesque
Copy link
Member

@anurse done: #18232

@halter73
Copy link
Member

halter73 commented Feb 4, 2020

We actually need to directly override ReadToEndAsync since it just Task.Runs ReadToEnd():

It looks like TextReader calls ReadAsyncInternal() in a loop. Problem is that ReadAsyncInternal() is implemented by Task.Factory.StartNewing Read(). So effectively the same thing.

The problem is it also looks like we need to override the following, most of which also call into ReadAsyncInternal(), in order to avoid async-over-sync:

  • public virtual Task<string?> ReadLineAsync()
  • public virtual ValueTask<int> ReadAsync(Memory<char> buffer, CancellationToken cancellationToken = default)
    • This is still async if MemoryMarshal.TryGetArray(buffer, ... succeeds, but sync otherwise
  • public virtual Task<int> ReadBlockAsync(char[] buffer, int index, int count)
  • public virtual ValueTask<int> ReadBlockAsync(Memory<char> buffer, CancellationToken cancellationToken = default)

@halter73
Copy link
Member

halter73 commented Feb 4, 2020

@davidfowl @anurse Why aren't we trying to make these improvements to TextReader itself? Do we know for some reason this kind of change wouldn't be accepted in the runtime repo?

@analogrelay
Copy link
Contributor

@halter73 I don't know that they wouldn't be accepted. We could open an issue and ask.

@analogrelay
Copy link
Contributor

Pre-planning: Runtime issue is in Future. If someone is going to fix this in 5.0 it'll have to be us. Given our resource constraints this might be something to defer to a later preview and see if there's interest in a community PR.

@analogrelay analogrelay added good first issue Good for newcomers. help wanted Up for grabs. We would accept a PR to help resolve this issue labels Mar 18, 2020
@davidfowl
Copy link
Member Author

@jkotalik isn't this done?

@BrennanConroy
Copy link
Member

@jkotalik says this should be done!

@ghost ghost locked as resolved and limited conversation to collaborators Jun 10, 2020
@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 subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-networking Includes servers, yarp, json patch, bedrock, websockets, http client factory, and http abstractions good first issue Good for newcomers. help wanted Up for grabs. We would accept a PR to help resolve this issue
Projects
None yet
Development

No branches or pull requests

8 participants