-
Notifications
You must be signed in to change notification settings - Fork 10k
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
Implement Kestrel Request PipeReader #7603
Conversation
For some reason I didn't have the option to make a draft PR 😢 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some commentary to guide feedback.
/// <summary> | ||
/// http://tools.ietf.org/html/rfc2616#section-3.6.1 | ||
/// </summary> | ||
public class ForChunkedEncoding : Http1MessageBody |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This class has very little changed from the original implementation. It now contains the RequestBodyPipe rather than MessageBody and continues to call PumpAsync().
src/Servers/Kestrel/Core/src/Internal/Http/ForChunkedEncodingMessageBody.cs
Outdated
Show resolved
Hide resolved
src/Servers/Kestrel/Core/src/Internal/Http/ForChunkedEncodingMessageBody.cs
Outdated
Show resolved
Hide resolved
src/Servers/Kestrel/Core/src/Internal/Http/ForContentLengthMessageBody.cs
Outdated
Show resolved
Hide resolved
src/Servers/Kestrel/Core/src/Internal/Http/ForContentLengthMessageBody.cs
Outdated
Show resolved
Hide resolved
src/Servers/Kestrel/Core/src/Internal/Http/ForUpgradeMessageBody.cs
Outdated
Show resolved
Hide resolved
src/Servers/Kestrel/Core/src/Internal/Http/HttpProtocol.FeatureCollection.cs
Show resolved
Hide resolved
src/Servers/Kestrel/Core/src/Internal/Http/ForContentLengthMessageBody.cs
Outdated
Show resolved
Hide resolved
src/Servers/Kestrel/Core/src/Internal/Http/ForContentLengthMessageBody.cs
Outdated
Show resolved
Hide resolved
src/Servers/Kestrel/Core/src/Internal/Http/ForContentLengthMessageBody.cs
Outdated
Show resolved
Hide resolved
src/Servers/Kestrel/Core/src/Internal/Http2/Http2MessageBody.cs
Outdated
Show resolved
Hide resolved
src/Servers/Kestrel/Core/src/Internal/Http/Http1ChunkedEncodingMessageBody.cs
Show resolved
Hide resolved
src/Servers/Kestrel/Core/src/Internal/Http/Http1ContentLengthMessageBody.cs
Show resolved
Hide resolved
src/Servers/Kestrel/Core/src/Internal/Http/Http1ContentLengthMessageBody.cs
Outdated
Show resolved
Hide resolved
while (true) | ||
{ | ||
// This isn't great. The issue is that TryRead can get a canceled read result | ||
// which is unknown to StartTimingReadAsync. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think I understand this. Shouldn't TryRead check IsCanceled and throw a BadHttpRequestException too?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Try* API shouldn’t throw. Makes them unusable, so we should avoid it where possible
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I was trying to avoid throwing in Try methods. However, TryRead throws internally in pipes, so we should consider fixing that in pipes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Try* API shouldn’t throw. Makes them unusable, so we should avoid it where possible
Like @jkotalik points out, TryRead is a little special. Errors also need to be raised from TryRead when the writer completes with an error. TryRead should only return false when the PipeReader is still active but there's no data available to currently read.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A little more info about the TryXXX pattern: TryXXX doesn't mean the method should never throw an exception. It means it shouldn't throw an exception for a certain use-case.
For example, int.TryParse will return false if the string cannot be parsed to an integer. But it will throw an ArgumentException if you give it an invalid NumberStyles value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TryRead should only return false when the PipeReader is still active but there's no data available to currently read.
Sure, it has to throw sometimes in those rare cases where the input is invalid. I don't know that I agree with the above.
src/Servers/Kestrel/Core/src/Internal/Http/Http1ContentLengthMessageBody.cs
Show resolved
Hide resolved
src/Servers/Kestrel/Core/src/Internal/Http/Http1ContentLengthMessageBody.cs
Outdated
Show resolved
Hide resolved
|
||
public override void OnWriterCompleted(Action<Exception, object> callback, object state) | ||
{ | ||
// TODO make this work with ContentLength. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
File an issue for this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will once I merge this PR.
src/Servers/Kestrel/Core/src/Internal/Http/Http1ContentLengthMessageBody.cs
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On the right track. I want so see better code sharing before I approve this.
Updated. I think I saw one test fail with timing (think there is a different exception message), I’ll take a look at it later today/tomorrow. |
|
18b8d40
to
c1799e1
Compare
Thanks! It's important to test the 3 clients under examples/clients run without issue. The functional tests use TestServer which I'm guessing will still use the stream adapters. |
@Eilon can we make this PR contingent on no gRPC regressions? I would be good to merge this today. |
@davidfowl contingent not just on some one-off gRPC testing, but on us asserting that the risk is low for all cases (preview 3 works just fine now, I don't want to break anything because we rushed). |
@Eilon tested against all HTTP2 clients in gRPC. This is a low risk change for gRPC because it barely changed anything with HTTP2 . See: https://github.com/aspnet/AspNetCore/pull/7603/files#diff-82d8f6d18b1c89f77b834073ac706d54R4 for the changes to HTTP2 . This effectively just exposes the underlying HTTP2 stream pipe. |
Approved for preview 3. |
All required checks passed. |
For #4757 and #4697.
This PR is the second half of exposing pipes in Kestrel. It does a few main things:
I would consider this PR semi-WIP. I think the overall design is solid, but there is some code duplication I can remove. I also want to add some more tests for Http2 message bodies and tests for ConsumeAsync. Finally, I think I'll need to add some benchmarks for Content-Length request reading and maybe add a few benchmark/inmemory scenarios too. Also, after scanning this PR, there is a lotttt of commented out code 🐋 .
cc/ @benaadams @shirhatti @JamesNK as I know you guys care 😄