Skip to content

Conversation

TheOneric
Copy link
Contributor

This addresses two issues:

First, until now if multiple encodings have been applied to the response body, the middleware would just skip over the unsupported algorithm and try to continue with the next. This likely crashes because the body now has the wrong data format for the next decompressor and is incorrect either way.

Furthermore, users may wish to use HEAD requests to check how much data would be transferred for a GET to decide whether to (proactively) load a resource or not. But the middleware used to just delete any content-length headers. Additionally, content-length headers are mandatory in HTTP1.0 and unless doing chunked transfers HTTP1.1, thus its absence might confuse later processing steps even for other requests types. The second commit changes the middleware to instead retain or update the content-length header.

For the second part, there are two points worth pointing out:

  • if there was previously no content-length header, this will now add one. I think this should be fine and it lead to simpler code, but if you think this should be changed let me know
  • i went with the approach from 5bc9b82 and assume a zero-byte binary as body implies a HEAD request and thus (effectively) also keep the original content-encoding header. Whether or not the content is compressed might also be of interest when doing HEAD requests (though i guess you could also argue one should omit the middleware entirely in this case, but then one needs to manually keep the accept-encoding header in sync with what the middleware supports)

If multiple Content-Encodings were applied restoring the original
message requires undoing all steps in reverse order.
Thus we cannot continue when encountering an unsupported codec. Just
skipping over one step will most likely just lead to decoding errors
in the next supported step or incorrect results otherwise.
HEAD requests can be used to check the size of remote content
to decide ahead of time whether it is worth fetching. Of course
the size after decompression likely differs from the transfer size
indicated in the content-length header, but depending on use case
only the transfer size might be relevant.

This obsoletes the empty-body special case in decompress_body
previously added in 5bc9b82
since HEAD requests are now handled earlier. If we get an
invalid empty body in a non-HEAD request we want to fail loudly.
Depending on context presence of this header is mandatory
or at least strongly encouraged in HTTP/1.0 and HTTP/1.1
and some later processing steps might rely on or profit
from its presence
@TheOneric TheOneric force-pushed the decompress-keep-content-length branch 2 times, most recently from fa0c87b to 7f4a78b Compare October 11, 2025 19:11
@TheOneric
Copy link
Contributor Author

Updated the patch to explicitly check for :head instead of equating all empty bodies to HEAD and content-length is only updated if it was set before. I hope this makes it now robust enough and sound for all possible scenarios.

But now I’m not sure what to do with the existing empty-body special case in decompression added in 5bc9b82. Should we keep or drop it? It was motivated by HEAD requests which we now filter out before it reaches this part. If we get an empty body here with a content-encoding applied and it’s not a HEAD request, it seems likely the connection prematurely broke off but wasn’t noticed.
On the other hand, while Tesla’s documentation only seems to allow for the atom versions of methods, in practice specifying string literals also seems to "work" and this wouldn’t be caught by the added :head check. Not sure if we need to consider API misuse here though

@yordis
Copy link
Member

yordis commented Oct 11, 2025

If it's a HEAD request, it's caught earlier. If it's not a HEAD request with empty body + content-encoding, it should fail loudly.

Unless I misunderstood https://datatracker.ietf.org/doc/html/rfc9110#name-head

Should we merge it now 🤔

@yordis
Copy link
Member

yordis commented Oct 11, 2025

btw, when in doubt, keep adding tests 😄

@TheOneric TheOneric force-pushed the decompress-keep-content-length branch from 7f4a78b to 3fda9ab Compare October 11, 2025 20:54
@TheOneric
Copy link
Contributor Author

If it's not a HEAD request with empty body + content-encoding, it should fail loudly.

Alright, updated the patch to remove the pre-existing empty-body special case then as it’s no longer needed.
Should be all good now i think

Copy link
Member

@yordis yordis left a comment

Choose a reason for hiding this comment

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

🚀 💜 Thank you so much for helping!

@yordis yordis merged commit 770055e into elixir-tesla:master Oct 11, 2025
6 checks passed
@TheOneric TheOneric deleted the decompress-keep-content-length branch October 11, 2025 21:34
yordis pushed a commit that referenced this pull request Oct 11, 2025
…dated content-length header (#809)

* fix: stop decompressing response on first unknown codec

If multiple Content-Encodings were applied restoring the original
message requires undoing all steps in reverse order.
Thus we cannot continue when encountering an unsupported codec. Just
skipping over one step will most likely just lead to decoding errors
in the next supported step or incorrect results otherwise.

* fix: keep original content length and encoding headers for HEAD requests

HEAD requests can be used to check the size of remote content
to decide ahead of time whether it is worth fetching. Of course
the size after decompression likely differs from the transfer size
indicated in the content-length header, but depending on use case
only the transfer size might be relevant.

This obsoletes the empty-body special case in decompress_body
previously added in 5bc9b82
since HEAD requests are now handled earlier. If we get an
invalid empty body in a non-HEAD request we want to fail loudly.

* fix: update existing content-length header after decompression

Depending on context presence of this header is mandatory
or at least strongly encouraged in HTTP/1.0 and HTTP/1.1
and some later processing steps might rely on or profit
from its presence

Signed-off-by: Yordis Prieto <[email protected]>
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