-
Notifications
You must be signed in to change notification settings - Fork 95
fix: accept an empty gzip as a valid input #349
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
base: main
Are you sure you want to change the base?
Conversation
d9fe493
to
bb750a2
Compare
bb750a2
to
dedb17b
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! A few feedback for the code
aebdbf5
to
ccdb74d
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks LGTM!
cc @robjtede can you have a double check please?
I think it's important to note that this is a degenerate case, and as such may actually break some expectations of other consumers. When we say "an empty gzip", we actually mean a real gzip file which decompresses to nothing. What were allowing here is just "an empty file" and pretending that's a valid gzip, which it isn't: $ touch a.gz
$ gunzip a.gz
gunzip: a.gz: unexpected end of file Tools like curl do try to be more lenient when the degenerate cases are obvious, such as empty response payloads. I haven't looked up whether it does this check itself or delegates to its decompression library. (I know in Actix Web, we have similar optimizations before calling into to our [de]compression libs.) I'm torn with async-compression, as a thin wrapper around these libraries, whether we should be putting any extra heuristics in place for this detection (is there any precedent for us doing this?) or whether the responsibility to implement this improvement should be given to Deno's client. @NobodyXu If we want to accept that responsibility for all our library's consumers then this impl LGTM. |
My personal view is that it's a bug in Deno that lead to this request, it shouldn't be trying to decompress something it knows is empty. |
Yeah, looking at the original issue seems like deno knows the body is empty before passing stuff to async-compression |
I also thought that the original issue can be solved only modifying deno codes, which turned out to be more difficult(for me) than I thought. resp.into_body().into_data_stream() (indirectly using sync-compression there) throws the "unexpected end of file" error and I have no idea how to verify if the file is empty before resp.into_body() or resp.into_body().into_data_stream(). (at least, I noticed that trying to read content-length in headers is useless, it almost always returns None) Of course, most likely there is a way to determine that it is empty before resp.into_body, but unfortunately I am not familiar with Rust yet and have not been able to find it. let body = loop {
match &mut *reader {
FetchResponseReader::BodyReader(reader) => break reader,
FetchResponseReader::Start(_) => {}
}
match std::mem::take(&mut *reader) {
FetchResponseReader::Start(resp) => {
let stream: BytesStream = Box::pin(
resp
.into_body()
.into_data_stream()
.map(|r| r.map_err(std::io::Error::other)),
);
*reader = FetchResponseReader::BodyReader(stream.peekable());
}
FetchResponseReader::BodyReader(_) => unreachable!(),
}
};
I see, not trying to decompress empty data is an ideal way. In the meantime, I'll give it one more try to see if changing the deno alone will solve the problem. |
Summary so farThe choices are
|
related: denoland/deno#29281
enabled gzip decoder to accept an empty gzip.
I added some test cases for this fix at tests/gzip.rs
reproduction
server_hasdata.js
server_nodata.js
client.js
result