-
Notifications
You must be signed in to change notification settings - Fork 327
[WIP] New Tide middleware: Automatic compression handling #117
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
Conversation
"gzip" => Some(Gzip), | ||
"deflate" => Some(Deflate), | ||
"identity" => Some(Identity), | ||
_ => None, |
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.
What is the difference between Some(Identity)
and None
? My understanding is that they're both treated the same way, so perhaps we could could combine these to make matching on them easier?
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.
Right now, the behavior for both is the same.
I suspect it might come in handy to have the explicit differentiation once quality value.
A request containing identity;q=0,unknown-compressio-algo
could (should?) respond 406 Not Acceptable
Overall this looks very promising! Thanks for putting in the work @kimsnj. Keen to see how this PR evolves! |
@kimsnj just checking in on this -- are you still planning to finish this PR? |
Hi @aturon, TLDR: I must admit I have a bit abandoned it the last few months due to other priorities, but could be back to it in the upcoming weeks if it's not taken in the meantime. Since the last update, I took a bit the time to play with Does this approach seems fine? Regarding this PR, should I close it in the meantime to avoid cluttering the pending ones on this repo, and re-open it once I have an update ? |
use futures::future::FutureObj; | ||
|
||
use crate::body::Body; | ||
use crate::{middleware::RequestContext, Middleware, 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.
Why not merge both into
use crate::{body::Body, middleware::RequestContext, Middleware, Response};
.iter() | ||
.filter_map(|hval| hval.to_str().ok()) | ||
.flat_map(|val| val.split(|c| c == ',')) | ||
.filter_map(|encoding| Encoding::parse(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.
.filter_map(|encoding| Encoding::parse(encoding)) | |
.filter_map(Encoding::parse) |
IIRC, clippy have a warning related to that.
let mut buf = Vec::new(); | ||
match encoding { | ||
Encoding::Gzip => { | ||
let mut gz = flate2::bufread::GzEncoder::new(body, flate2::Compression::fast()); |
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.
Should we not use flate2::Compression::default()
rather than flate2::Compression::fast()
?
} | ||
|
||
fn apply(body: &[u8], encoding: Encoding) -> Option<Vec<u8>> { | ||
let mut buf = Vec::new(); |
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 wonder if this buf
is being allocated even if there is no encoding to be done (see the None
block below)?
As well, I think it might be possible to not have an Option
returned here with compile-time checking?
@kimsnj I'm willing to try working on this WIP middleware if you're busy, though it might happen in a separate PR. |
@fairingrey I'll close this PR for now so that you can pick it up if you want and are available. If this is of any help, here is a gist where I played around with flate API. I planned to use something like |
Description
This PR aims at brining a new compression handling middleware to Tide.
The goal of it would to automatically:
This is still work-in-progress for several reasons:
Missing features:
Some target features are not there yet (but I guess this could come with time)
Streaming compression
I struggled (and actually didn't manage) to compress the body as a stream of chunks.
Trying to use the
Stream
impl ofhyper::Body
, I encountered a few challenges:flate2
interface. Can theAsyncRead
/AsyncWrite
version be used?I guess I should probably manually implement a
Stream
and callflate2::Compress
raw struct.Any hint on how to best go about this are very welcome :)
Meanwhile, to get something working, I used
read_to_vec
ontide::Body
. This works well for small response… But will put more memory pressure payloads (e.g. streaming a file compressed).Error handling
For some errors, it is quite straight-forward to have a fallback behaviour (e.g. if compression fails, return body as is), but others are un-clear to me (e.g. what should happen in
read_to_vec
fails?).Motivation and Context
This follows from issue #26
How Has This Been Tested?
curl
with various headersTypes of changes
Checklist: