Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Don't assume 1xx (101) should have the (streaming) body stripped by Rack::Response. #1987

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

Closed
wants to merge 3 commits into from

Conversation

ioquatix
Copy link
Member

This is required to use Rack::Response for generating streaming responses. Otherwise, for 101 status codes, it will strip the body.

Alternatives include changing Rack::Response#finish to not do any stripping, and leave it up to the sever (to fail would probably be the best, generating content for a No Content or Not Changed response seems at best weird and at worst a bug).

@ioquatix ioquatix force-pushed the rack-response-streaming-body-to_a branch from b982e29 to 9f79a1e Compare November 28, 2022 00:15
@ioquatix ioquatix force-pushed the rack-response-streaming-body-to_a branch from 9f79a1e to b5b5cac Compare November 28, 2022 00:18
@ioquatix
Copy link
Member Author

@jeremyevans stripping headers and effectively setting an empty body in Rack::Response#finish seems like we are plastering over user errors.

STATUS_WITH_NO_ENTITY_BODY relates to ENTITY BODIES and I'm almost certain that semantically, 101 does not have an "ENTITY BODY" but changes the connection type entirely to a raw socket (or stream, etc). I'm not sure if HTTP/2 considers a CONNECT request to have an "ENTITY BODY" or just refers to it as a bidirectional stream. Terminology aside, it feels like if the user decided to make an invalid response, the server should be responsible for saying: "You doofus, you are returning a 204 response AND content! Fail!" rather than Rack::Response silently cleaning up the mess.

In that case, I'd vote for Rack::Response#to_a to bypass this logic entirely. We could leave Rack::Response#finish as is or remove the logic too (but it might be a breaking change).

@jeremyevans
Copy link
Contributor

RFC 2616 and 7231 (HTTP 1.1) do not allow bodies for any 1xx responses:

RFC 7540 (HTTP 2) seems to imply 101 can have a body (https://datatracker.ietf.org/doc/html/rfc7540#section-8.1.3).

So it would probably be best to only keep the body for 101 if HTTP 2 is the protocol in use.

@ioquatix
Copy link
Member Author

There is no technical limitation for HTTP/2 to have a response body for any status code. This is different from HTTP/1 where the client will literally break because it affects the protocol parser state. I personally think that the server itself should enforce the semantics of the protocol, but I'm not against the Rack::Response doing it too. However it seems a little redundant.

You are correct that HTTP/1 101 status code does not officially have a body in the typical sense of all other HTTP/1 responses. However we treat it as equivalent for the sake of convenience and this distinction is unimportant for HTTP/2 since it does not have an upgrade mechanism.

(1) Since servers already have to do this (or risk being totally broken), why is it also important for Rack::Response to do it?

(2) Your proposal of handling 101 for HTTP/2 doesn't make sense since HTTP/2 doesn't use 101 upgrade mechanism. So do you agree with this PR or want additional changes or a different approach entirely?

@jeremyevans
Copy link
Contributor

If this doesn't matter for HTTP/2, and the HTTP/1.1 RFCs do not allow for a body for any 1xx response, I would leave the current behavior. Why would we want to break backwards compatibility to allow something that isn't allowed by the RFCs? If you want to allow the new behavior, the new behavior needs to be optional and off by default. If you want to change the default behavior, you need to put the change through a normal deprecation cycle (warning for all responses with bodies where you will change the behavior) before the default behavior is changed in Rack 4.

@ioquatix
Copy link
Member Author

Can you explain how one is supposed to send a 101 upgrade with a streaming response body using Rack::Response?

@ioquatix
Copy link
Member Author

To clarify:

HTTP/1.1 RFCs do not allow for a body for any 1xx response

They do not allow for an entity body which I would argue is only a subset of Rack's concept of a response body (i.e. a streaming response body can be used for an upgrade request).

In other words, it's perfectly valid to return [101, ..., proc{...}] so why is it not valid to return Rack::Response[101, ..., proc{...}] (as Rack::Response essentially breaks the response body).

@@ -537,7 +537,11 @@ def context(env, app = @app)
}

# Responses with HTTP status codes that should not have an entity body
STATUS_WITH_NO_ENTITY_BODY = Hash[((100..199).to_a << 204 << 304).product([true])]
STATUS_WITH_NO_ENTITY_BODY = {
100 => true,
Copy link
Member Author

@ioquatix ioquatix Nov 28, 2022

Choose a reason for hiding this comment

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

I'd be happy to add 102 and 103 to this list.

Alternatively, we could just remove this check entirely from Rack::Response which is probably slightly more correct (servers MUST implement it anyway, otherwise raw [status, headers, body] response could break the connection). However, this breaks more tests which assume Rack::Response cleans things up in this regard.

@jeremyevans
Copy link
Contributor

To clarify:

HTTP/1.1 RFCs do not allow for a body for any 1xx response

They do not allow for an entity body which I would argue is only a subset of Rack's concept of a response body (i.e. a streaming response body can be used for an upgrade request).

Thank you for explaining the difference.

In other words, it's perfectly valid to return [101, ..., proc{...}] so why is it not valid to return Rack::Response[101, ..., proc{...}] (as Rack::Response essentially breaks the response body).

So for 101 (or all 1xx, 204, 302 statuses), passing a callable body through without changes seems reasonable. However, I think an enumerable body should still be replaced with an empty array.

@ioquatix ioquatix closed this Dec 5, 2022
@ioquatix ioquatix deleted the rack-response-streaming-body-to_a branch December 5, 2022 05:03
@ioquatix ioquatix mentioned this pull request Jan 25, 2023
7 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants