Skip to content
This repository has been archived by the owner on Jan 23, 2023. It is now read-only.
/ corefx Public archive

Streamline SocketHttpHandler's ParseStatusLine validation #27163

Merged
merged 2 commits into from
Feb 15, 2018

Conversation

stephentoub
Copy link
Member

@stephentoub stephentoub commented Feb 15, 2018

For a typical status line like "HTTP/1.1 200 OK", cuts the time of ParseStatusLine almost in half.
Fixes https://github.com/dotnet/corefx/issues/26946

cc: @geoffkizer, @davidsh

For a typical status line like "HTTP/1.1 200 OK", cuts the time of ParseStatusLine almost in half.
@@ -36,6 +36,8 @@ public Version Version
}
}

internal void SetVersionUnchecked(Version value) => _version = value;

Choose a reason for hiding this comment

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

The equivalent API for headers is called "TryAddWithoutValidation". Not sure this is better than just "Unchecked", but maybe we should be consistent.

Copy link
Member Author

Choose a reason for hiding this comment

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

Ok, will rename.

@@ -635,73 +637,78 @@ private CancellationTokenRegistration RegisterCancellation(CancellationToken can
// TODO: Remove this overload once https://github.com/dotnet/roslyn/issues/17287 is addressed
// and the compiler doesn't lift the span temporary from the call site into the async state
// machine in debug builds.
private void ParseStatusLine(ArraySegment<byte> line, HttpResponseMessage response) =>
private static void ParseStatusLine(ArraySegment<byte> line, HttpResponseMessage response) =>

Choose a reason for hiding this comment

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

Since you're in this code anyway :), can we remove this overload per comment above?

Copy link
Member Author

Choose a reason for hiding this comment

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

Unfortunately, no, the C# compiler still prevents span locals in an async method. @VSadov, is there an open issue tracking that I can link to? The overall issue I linked to above is closed.

else
{
byte minorVersion = line[7];
line[7] = (byte)'1'; // Enable checking the first 7 bytes easily by comparing against HTTP/1.1

Choose a reason for hiding this comment

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

It's a little weird to modify the buffer. This code isn't perf critical, would it be better to just do something dumb here?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, went back and forth on that. It shouldn't matter that we're modifying it, but I could do the "simpler" thing and just add the per-char comparisons here... unfortunately that simpler thing is actually longer, but whatever 😄

Choose a reason for hiding this comment

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

Yeah... to make it smaller, we could possibly just have a static byte[] for "HTTP/1." and do some sort of sequence based comparison (is there a Span.SequenceEquals?)

Copy link
Member Author

Choose a reason for hiding this comment

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

There is. I'll do that.

ThrowInvalidHttpResponse();
Span<byte> reasonBytes = line.Slice(MinStatusLineLength + 1);
string knownReasonPhrase = HttpStatusDescription.Get(response.StatusCode);
response.SetReasonPhraseUnchecked(knownReasonPhrase != null && EqualsOrdinal(knownReasonPhrase, reasonBytes) ?

Choose a reason for hiding this comment

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

Seems like we should still validate unknown reason phrases -- either add the logic here specifically and throw on failure, or just call the checked API.

See #26946 also, which is probably a good argument for adding the logic here.

Copy link
Member Author

Choose a reason for hiding this comment

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

Seems like we should still validate unknown reason phrases

We already did. The only thing it validates is that it doesn't contain \r or \n and that it's not null, and none of those could be the case here.

Choose a reason for hiding this comment

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

Can we reenable the test for #26946 and close the issue, then?

Copy link
Member Author

Choose a reason for hiding this comment

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

Actually, I'm wrong. I thought our line parsing was looking for \r, but it's now looking for \n, which means a \r could still be here. I'll make the unknown phrase still use the checking logic.

Copy link
Member Author

Choose a reason for hiding this comment

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

(but I'll fix the issue with that test and re-enable it anyway)

@geoffkizer
Copy link

LGTM

@wfurt
Copy link
Member

wfurt commented Feb 15, 2018

how did you measure the improvement @stephentoub ???

@stephentoub
Copy link
Member Author

how did you measure the improvement

I temporarily modified the binary to expose HttpConnection.ParseStatusLine as a public method. Then I wrote a little microbenchmark against that.

@wfurt
Copy link
Member

wfurt commented Feb 15, 2018

thanks for the explanation.

@stephentoub
Copy link
Member Author

😄

@stephentoub
Copy link
Member Author

None of the failures are real; they're all do the test infrastructure problems we've been facing the last few days.

@stephentoub stephentoub merged commit c8d23b4 into dotnet:master Feb 15, 2018
@stephentoub stephentoub deleted the streamline_parse_status branch February 15, 2018 21:04
A-And pushed a commit to A-And/corefx that referenced this pull request Feb 21, 2018
* Streamline SocketHttpHandler's ParseStatusLine validation

For a typical status line like "HTTP/1.1 200 OK", cuts the time of ParseStatusLine almost in half.

* Address PR feedback
@karelz karelz added this to the 2.1.0 milestone Mar 10, 2018
picenka21 pushed a commit to picenka21/runtime that referenced this pull request Feb 18, 2022
…efx#27163)

* Streamline SocketHttpHandler's ParseStatusLine validation

For a typical status line like "HTTP/1.1 200 OK", cuts the time of ParseStatusLine almost in half.

* Address PR feedback


Commit migrated from dotnet/corefx@c8d23b4
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants