Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Add folded response header support to SocketsHttpHandler - #27727

Merged
stephentoub merged 2 commits into
dotnet:masterfrom
stephentoub:httpmultiline
Mar 5, 2018
Merged

stephentoub merged 2 commits into
dotnet:masterfrom
stephentoub:httpmultiline

Conversation

@stephentoub

Copy link
Copy Markdown
Member

The feature is deprecated by RFC 7230, but some servers still utilize it, and if they do, SocketsHttpHandler currently fails (WinHttpHandler and the netfx handler both allow it, CurlHandler currently fails as well). This commit updates the header parsing logic to allow for them.

cc: @geoffkizer, @davidsh

// to RFC 7230 3.2.4, a valid approach to dealing with them is to "replace each
// received obs-fold with one or more SP octets prior to interpreting the field
// value or forwarding the message downstream", so that's what we do.
_readBuffer[lfIndex] = (byte)' ';

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This shouldn't be necessary. TryAddWithoutValidation can handle embedded newlines. I.e. this works fine and produces the same result as if \r\n was not present:

            var request = new HttpRequestMessage();
            request.Headers.TryAddWithoutValidation("Accept", "text/html,\r\n */*");
            foreach (var v in request.Headers.Accept)
            {
                Console.WriteLine(v);
            }

@stephentoub stephentoub Mar 5, 2018 •

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

It doesn't always normalize them, e.g. this:

var request = new HttpRequestMessage();
request.Headers.TryAddWithoutValidation("FooBar", "this is a \r\n\t    test");
foreach (string v in request.Headers.GetValues("FooBar"))
{
    Console.WriteLine(v);
}

produces:

this is a
            test

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Interesting. Maybe it should? Or if not TryAddWithoutValidation, perhaps when the value is retrieved? There's a whole process here about when stuff is validated/parsed/normalized. If we can just reuse that, it would be nice. Let me look into this real quick.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

What's interesting is that we specifically check for this situation in HttpHeaders.ParseSingleRawHeaderValue. A header value with "\r\n" followed by space or tab is considered valid; one with "\r\n" followed by anything else is not.

If you change the code above to

request.Headers.TryAddWithoutValidation("FooBar", "this is a \r\ntest");

Then you'll get an exception of GetValues("FooBar") saying that the FooBar header was not found.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

It seems to me that the validation logic in ParseSingleRawHeaderValue should remove the \r\n -- that seems most in keeping with what this logic is intended to do, which is to produce a validated header value.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I'll open an issue for it. Changing that shared logic is a much more impactful change than the localized one I have here, and I don't want to block this on that broader issue.

// Parse the response status line.
var response = new HttpResponseMessage() { RequestMessage = request, Content = new HttpConnectionResponseContent() };
ParseStatusLine(await ReadNextLineAsync().ConfigureAwait(false), response);
ParseStatusLine(await ReadNextResponseHeaderLineAsync().ConfigureAwait(false), response);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Folding should only be valid for header fields, not for status line.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Fixed.

@geoffkizer

Copy link
Copy Markdown

Since the perf impact seems negligible, I think we should do this.

The feature is deprecated by RFC 7230, but some servers still utilize it, and if they do, SocketsHttpHandler currently fails (WinHttpHandler and the netfx handler both allow it, CurlHandler currently fails as well).  This commit updates the header parsing logic to allow for them.
@stephentoub
stephentoub merged commit dc355e9 into dotnet:master Mar 5, 2018
@stephentoub
stephentoub deleted the httpmultiline branch March 5, 2018 20:32
@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
…fx#27727)

* Add folded response header support to SocketsHttpHandler

The feature is deprecated by RFC 7230, but some servers still utilize it, and if they do, SocketsHttpHandler currently fails (WinHttpHandler and the netfx handler both allow it, CurlHandler currently fails as well).  This commit updates the header parsing logic to allow for them.

* Address PR feedback


Commit migrated from dotnet/corefx@dc355e9
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.

4 participants