-
Notifications
You must be signed in to change notification settings - Fork 100
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
Replace reqwest's auto-decompression with a custom one #241
Conversation
Neither do |
also warn if content-length is zero
Edit: This doesn't seem to be a trivial thing so maybe we should look into it in the future. |
@@ -423,14 +428,16 @@ impl Printer { | |||
|
|||
pub fn print_response_body( | |||
&mut self, | |||
mut response: Response, | |||
response: &mut Response, |
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.
Incidentally, this is just the change I needed in #240 i.e not consuming Response so response_meta
can be accessed later.
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.
Works great! Just a few small suggestions left. Sorry for taking a while to review.
src/printer.rs
Outdated
let encoding = encoding.or_else(|| get_charset(&response)); | ||
let encoding = encoding.or_else(|| get_charset(response)); | ||
let compression_type = get_compression_type(response.headers()); | ||
let mut body = decompress_stream(response, compression_type); |
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.
The error for failing to decode changes from error decoding response body: unexpected end of file
to failed to fill whole buffer
, which is a little worse.
HTTPie's is ContentDecodingError: ('Received response with content-encoding: gzip, but failed to decode it.', error('Error -3 while decompressing data: incorrect header check'))
, which is messy but informative.
I don't think this is a blocking problem and I don't know how to solve it, but I figured I'd make a note.
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.
I think I did notice the change in the error message, but I can't remember the steps to reproduce it. Did you set up a server that returns the wrong content-encoding
?
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.
Yep, with flask:
from flask import Flask
app = Flask(__name__)
@app.route('/badgz')
def badgz():
return 'bad', {'Content-Encoding': 'gzip'}
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. So the piece I was missing is that small responses lead to unexpected end of file
failed to fill whole buffer
while anything else will return the underlying error i.e corrupt deflate stream
or invalid gzip header
.
Slightly related, I was thinking of improving decompression error messages by modifying decompress()
to return a Decompress/Decode wrapper that implements Read and prepends errors with error decoding response body
. However, only io errors can be returned from the Read trait's methods so that is a dead end (I think).
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.
You can add a custom message to an io::Error
.
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.
Nice, I will try using that now.
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.
We should call no_gzip
and friends in case the reqwest features get re-enabled somehow.
One side effect from this PR is that the
--download
flag no longer decompresses responses
How hard would this be to fix? Could we wrap decompress_stream
around pb.wrap_read(response)
or is there another obstacle I'm missing?
We could even make copy_largebuf
return the number of bytes actually written, and print that as an extra message if it doesn't match the progress bar. (But that might be overkill for something the server shouldn't do to begin with.)
ac17d1a
to
cdf9591
Compare
I will be leaving out this part since I am not sure what is the best way to display the extra information. |
ef4aa70
to
9a6f6fe
Compare
src/utils.rs
Outdated
match self { | ||
Decoder::PlainText(decoder) => decoder.read(buf), | ||
Decoder::Gzip(decoder) => decoder.read(buf).map_err(|e| { | ||
io::Error::new(e.kind(), format!("error decoding response body: {}", e)) |
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.
Can you mention the compression type here?
src/utils.rs
Outdated
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { | ||
match self { | ||
Decoder::PlainText(decoder) => decoder.read(buf), | ||
Decoder::Gzip(decoder) => decoder.read(buf).map_err(|e| { |
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.
To tell the difference between a decompression error and an I/O error this scheme would be possible:
- Add another wrapper between
GzDecoder
andR
- If
R
returns an error, set abool
field in that wrapper - If
GzDecoder
returns an error, useget_ref()
to check that field- If it's
false
, the error happened while decompressing
- If it's
I don't know if that's worth the effort.
a9763f1
to
7d1a47f
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.
Wonderful!
Doing so will allow us to preserve
Content-Encoding
andContent-Length
for compressed responses. This also opens the door for handling responses from servers that misinterpret thedeflate
encoding asdeflate
instead ofdeflate + zlib headers
e.gxh example.org accept-encoding:deflate
.One side effect from this PR is that the--download
flag no longer decompresses responses but since we are explicitly sendingaccept-identity: identity
and HTTPie doesn't handle it perfectly either, maybe we can ignore it?Fixes #210