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

Implement Kestrel Request PipeReader #7603

Merged
merged 29 commits into from
Feb 22, 2019

Conversation

jkotalik
Copy link
Contributor

For #4757 and #4697.

This PR is the second half of exposing pipes in Kestrel. It does a few main things:

  • Makes Content-Length requests directly read from the connection pipe rather than from a request pipe
  • Moves RequestPipe logic (PumpAsync) into the Chunked message body.
  • Changes Streams => BodyControl and makes all body control calls be done through the HttpRequestPipeReader/HttpResponsePipeWriter

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 😄

@jkotalik
Copy link
Contributor Author

For some reason I didn't have the option to make a draft PR 😢

Copy link
Contributor Author

@jkotalik jkotalik left a 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
Copy link
Contributor Author

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().

@jkotalik jkotalik added this to the 3.0.0-preview3 milestone Feb 15, 2019
@jkotalik jkotalik changed the title [WIP] Implement Kestrel Request PipeReader Implement Kestrel Request PipeReader Feb 16, 2019
while (true)
{
// This isn't great. The issue is that TryRead can get a canceled read result
// which is unknown to StartTimingReadAsync.
Copy link
Member

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?

Copy link
Member

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

Copy link
Contributor Author

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.

Copy link
Member

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.

Copy link
Member

@JamesNK JamesNK Feb 19, 2019

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.

Copy link
Member

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.


public override void OnWriterCompleted(Action<Exception, object> callback, object state)
{
// TODO make this work with ContentLength.
Copy link
Member

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.

Copy link
Contributor Author

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.

Copy link
Member

@halter73 halter73 left a 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.

@jkotalik
Copy link
Contributor Author

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.

@benaadams
Copy link
Member

benaadams commented Feb 19, 2019

Conflicting files
`src/Servers/Kestrel/test/InMemory.FunctionalTests/RequestTests.cs`

@JamesNK
Copy link
Member

JamesNK commented Feb 22, 2019

Yes, but I will verify now by running it against gRPC.

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.

@davidfowl
Copy link
Member

@Eilon can we make this PR contingent on no gRPC regressions? I would be good to merge this today.

@Eilon
Copy link
Member

Eilon commented Feb 22, 2019

@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).

@jkotalik
Copy link
Contributor Author

@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.

@Eilon
Copy link
Member

Eilon commented Feb 22, 2019

Approved for preview 3.

@jkotalik
Copy link
Contributor Author

All required checks passed.

@jkotalik jkotalik merged commit 57092e9 into release/3.0-preview3 Feb 22, 2019
@jkotalik jkotalik deleted the jkotalik/kestrelRequestPipe branch February 22, 2019 16:26
@amcasey amcasey added area-networking Includes servers, yarp, json patch, bedrock, websockets, http client factory, and http abstractions and removed area-runtime labels Jun 6, 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.

8 participants