-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
Problems with Content-Length and Transfer-Encoding #2427
Comments
Thanks for the write-up, yea let's fix this! Not that you have to, but since you quoted a few types internal to hyper, do you have a suggestion for how to adjust the code to fix these? It's fine if they need separate fixes, we can make small PRs if need be... |
I think the I've put together a draft, jeddenlea@c5dd693 Are there some regression tests for all of this I could take a look at and alter if necessary? |
I agree that those functions are confusing. There's tests in Want to post what you have in PR? |
@seanmonstar sure! I think I've cleaned it up enough to maybe actually work. #2432 I'm still not 100% happy with the new |
I'm new enough to Rust that it took me a while just to figure out how to run the tests under /tests/, but they've proven helpful! I'm also fairly new to Hyper in general, so I'm not sure what patterns are broadly used with it. I'm struggling a little bit to come up with an answer that fits all cases without potentially causing unexpected regressions for existing use cases. For instance, take a HEAD request. I would expect most naive services to not handle GET or HEAD differently, and if it doesn't set Content-Length itself, it'll be inferred from the And, So, I'm trying to make |
I think we need to keep |
I am worried about breaking the similarity too. However, having maybe made it work in my draft, it doesn't appear to be as bad as I had feared. The changes to behavior are all reasonable, at least. Maybe some projects' test suites will require subtle adjusting, but there are no actual substantive changes. Everything is equivalent on the wire. First, which should not be controversial, 204s, any 1xx, and any 2xx response to a CONNECT will now never have either Content-Length or Transfer-Encoding. This is an essential fix. The more worrying subtle changes happen with empty bodies on HEAD requests and 304 responses...
Of the changes, the worst really are the addition of I've considered allowing the addition of |
On the 304 front, the most conservative change we could make could be to simply never guess For HEADs, unfortunately I don't think there's a clean path forward without potentially changing something in a way which someone may find unexpected. I imagine there may be some accidental, incorrect |
Fixes hyperium#2427 204s must never have either Content-Length or Transfer-Encoding headers. Nor should any 1xx response. Nor should any 2xx response made to a CONNECT request. On the other hand, any other kind of response may have either a Content-Length or Transfer-Encoding header. This includes 304s in general, and any response made to a HEAD request. In those of those cases, the headers should match what would have been sent with a normal response. The trick then is to ensure that such headers are not mis-inferred. When responding to a HEAD request, a service may reasonably opt out of computing the full response, and thus may not know how large it would be. To add automatically add `Content-Length: 0` would be a mistake. As Body::empty() seems to be the defacto "no response" Body, it shall be used as such. If a service responds to a HEAD request, or to a conditional GET request with a 304, it may specify Body::empty() as the body, and no Content-Length or Transfer-Encoding header will be added. In all other cases when a Content-Length header is required for HTTP message framing, `Content-Length: 0` will be still automatically added. Body::from("") on the other hand will now implie a specific empty Body. It will continue to imply `Content-Length: 0` in all cases, now including a 304 response. Either Content-Length or Transfer-Encoding may be added explicitly as headers for either HEAD requests or 304 responses.
Fixes hyperium#2427 204s must never have either Content-Length or Transfer-Encoding headers. Nor should any 1xx response. Nor should any 2xx response made to a CONNECT request. On the other hand, any other kind of response may have either a Content-Length or Transfer-Encoding header. This includes 304s in general, and any response made to a HEAD request. In those of those cases, the headers should match what would have been sent with a normal response. The trick then is to ensure that such headers are not mis-inferred. When responding to a HEAD request, a service may reasonably opt out of computing the full response, and thus may not know how large it would be. To add automatically add `Content-Length: 0` would be a mistake. As Body::empty() seems to be the defacto "no response" Body, it shall be used as such. If a service responds to a HEAD request, or to a conditional GET request with a 304, it may specify Body::empty() as the body, and no Content-Length or Transfer-Encoding header will be added. In all other cases when a Content-Length header is required for HTTP message framing, `Content-Length: 0` will be still automatically added. Body::from("") on the other hand will now implie a specific empty Body. It will continue to imply `Content-Length: 0` in all cases, now including a 304 response. Either Content-Length or Transfer-Encoding may be added explicitly as headers for either HEAD requests or 304 responses.
Fixes hyperium#2427 204s must never have either Content-Length or Transfer-Encoding headers. Nor should any 1xx response. Nor should any 2xx response made to a CONNECT request. On the other hand, any other kind of response may have either a Content-Length or Transfer-Encoding header. This includes 304s in general, and any response made to a HEAD request. In those of those cases, the headers should match what would have been sent with a normal response. The trick then is to ensure that such headers are not mis-inferred. When responding to a HEAD request, a service may reasonably opt out of computing the full response, and thus may not know how large it would be. To add automatically add `Content-Length: 0` would be a mistake. As Body::empty() seems to be the defacto "no response" Body, it shall be used as such. If a service responds to a HEAD request, or to a conditional GET request with a 304, it may specify Body::empty() as the body, and no Content-Length or Transfer-Encoding header will be added. In all other cases when a Content-Length header is required for HTTP message framing, `Content-Length: 0` will be still automatically added. Body::from("") on the other hand will now implie a specific empty Body. It will continue to imply `Content-Length: 0` in all cases, now including a 304 response. Either Content-Length or Transfer-Encoding may be added explicitly as headers for either HEAD requests or 304 responses.
This could potentially be seen as a couple of different issues, but they're all tightly overlapping, and can probably all be solved with a common fix. This also overlaps with #2215.
Currently,
Content-Length: 0
may be automatically applied to any 204 response (just like 101 responses in #2215). Also, otherContent-Length
headers can be set explicitly within a service, or be implied by a body with aKnownLength
. A 204 response MUST NOT contain eitherContent-Length
orTransfer-Encoding
.On the other hand, a 304 response will never have a body, but MAY contain either
Content-Length
orTransfer-Encoding
. Currently, the only way to get aContent-Length
header attached to a 304 response is to try to actually send a Body of that length.The headers made in response to a
HEAD
request should match those which would have been made for aGET
request. Currently, if a service attempts to force chunked encoding on what might otherwise imply aContent-Length
header be added,GET
requests will seeTransfer-Encoding: chunked
while aHEAD
request receivesContent-Length: ...
. It is not currently possible to setTransfer-Encoding
on a response to aHEAD
request.It seems the things which need to be fixed are:
CONNECT
request, anyContent-Length
orTransfer-Encoding
header set by a service must be dropped. Further, neither header should be automatically added.Content-Length
orTransfer-Encoding
header set by a service for any kind of response should be handled the same forGET
andHEAD
requests.Content-Length
orTransfer-Encoding
header set by a service for a 304 response should be left alone. (perhaps unless aBodySize::Known
greater than 0 conflicts with aContent-Length
header, which could be an error?)For reference, https://httpwg.org/specs/rfc7230.html#rfc.section.3.3
The text was updated successfully, but these errors were encountered: