Skip to content

Fix compression middleware images #2996

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

Open
wants to merge 13 commits into
base: master
Choose a base branch
from

Conversation

cptrodolfox
Copy link
Contributor

@cptrodolfox cptrodolfox commented Mar 8, 2023

PR Type

Adds predicate for compression of responses with default value that skips compression for video and images.

PR Checklist

  • Tests for the changes have been added / updated.
  • Documentation comments have been added / updated.
  • A changelog entry has been made for the appropriate packages.
  • Format code with the latest stable rustfmt.
  • (Team) Label with affected crates and semver status.

Overview

Closes #2981

@robjtede robjtede added this to the actix-web v4.4 milestone Mar 12, 2023
@robjtede robjtede added B-semver-minor A-web project: actix-web labels Mar 12, 2023
@robjtede
Copy link
Member

The solution to this issue should allow user customization of the excluded mime types.

@cptrodolfox
Copy link
Contributor Author

The solution to this issue should allow user customization of the excluded mime types.

Thanks, I will take it mind.

@cptrodolfox
Copy link
Contributor Author

The solution to this issue should allow user customization of the excluded mime types.

So, I was taking a look into the Compress struct that is used to build the CompressMiddleware. And, I think that a good solution would be to add a field to the struct that holds a function fn(Mime) -> bool. This function would be the one to indicate whether or not we should compress content based on the Mime type of the Content-type header. WDYT @robjtede .

#[derive(Debug, Clone)]
#[non_exhaustive]
pub struct Compress {
    pub compress: fn(Mime) -> bool,
}

impl Default for Compress {
    fn default() -> Self {
	Compress {
	    compress: |_| { true }
	}
    }
}

@robjtede
Copy link
Member

Use of a predicate function is a good idea imo. Then we just set the default to ignore images to solve #2981.

@cptrodolfox
Copy link
Contributor Author

Only one question for the moment @robjtede. How do we return an uncompressed response?. After skimming through the code. I believe the decision to compress or not should be done in the Future implementation of CompressResponse (Am I correct on thinking this?). If I understand correctly, the snippet Encoder::response(enc, head, body) is where the actual compression takes place.

@cptrodolfox
Copy link
Contributor Author

cptrodolfox commented Mar 15, 2023

@robjtede I was able to add a proof of concept of using a predicate function for deciding whether or not to compress based on the value of the Content-Type header of the response. I think there are points to improve though the first one is that currently the compress function has the following signature fn(Option<&HeaderValue>) -> bool, I had to use the HeaderValue since the headers map of the head of the response only returns this. Also, I had to change a little bit the signature of the poll function of the Future implementation of the CompressResponse struct, I am not sure what this change entails but it was needed to call the compress predicate function. What are your thoughts?

@robjtede
Copy link
Member

robjtede commented Apr 2, 2023

@cptrodolfox I spent some time working on this PR today but I can't push to your branch. Can you check the settings for this PR?

Alternatively, apply this patch here: 0216cb1

@cptrodolfox cptrodolfox marked this pull request as ready for review April 10, 2023 20:45
@cptrodolfox
Copy link
Contributor Author

@cptrodolfox I spent some time working on this PR today but I can't push to your branch. Can you check the settings for this PR?

Alternatively, apply this patch here: 0216cb1

Hey @robjtede, It appears since the fork is from a organization I can not change the "Allow edit from maintainers" setting. I will apply manually the patch you mentioned.

@cptrodolfox
Copy link
Contributor Author

@cptrodolfox I spent some time working on this PR today but I can't push to your branch. Can you check the settings for this PR?
Alternatively, apply this patch here: 0216cb1

Hey @robjtede, It appears since the fork is from a organization I can not change the "Allow edit from maintainers" setting. I will apply manually the patch you mentioned.

Hey @robjtede , I have added the changes you made. I look through the changes. And, If you don't mind, I want to ask you the following: What is the idea behind using a counted reference for predicate?

@robjtede
Copy link
Member

The advantage over taking a function pointer is that you can still avoid the generic param and also pass closures as well.

@robjtede robjtede requested a review from a team April 10, 2023 23:48
@cptrodolfox
Copy link
Contributor Author

The advantage over taking a function pointer is that you can still avoid the generic param and also pass closures as well.

Thanks for the answer.

@robjtede
Copy link
Member

robjtede commented Apr 11, 2023

Should be noted that some auto traits are lost in this PR, wondering if this is okay.

https://github.com/actix/actix-web/actions/runs/4662131547/jobs/8252158730?pr=2996#step:6:410

Removed items from the public API
=================================
-impl core::marker::Send for actix_web::middleware::Compress
-impl core::marker::Sync for actix_web::middleware::Compress
-impl core::panic::unwind_safe::RefUnwindSafe for actix_web::middleware::Compress
-impl core::panic::unwind_safe::UnwindSafe for actix_web::middleware::Compress

@cptrodolfox
Copy link
Contributor Author

Should be noted that some auto traits are lost in this PR, wondering if this is okay.

https://github.com/actix/actix-web/actions/runs/4662131547/jobs/8252158730?pr=2996#step:6:410

Removed items from the public API
=================================
-impl core::marker::Send for actix_web::middleware::Compress
-impl core::marker::Sync for actix_web::middleware::Compress
-impl core::panic::unwind_safe::RefUnwindSafe for actix_web::middleware::Compress
-impl core::panic::unwind_safe::UnwindSafe for actix_web::middleware::Compress

I am unsure if losing these traits would affect users down stream. If so we might want to implement them, manually. WDYT @robjtede

@robjtede
Copy link
Member

From the rebase this needs a rustfmt run.

On the blocker for merging this, I'd be willing to give up the UnwindSafe impls but not so much Send and Sync, unfortunately. I can definitely think of common patterns where it would break and that's not acceptable. Thinking about how to progress, though it'll probably just be holding off until v5.0 for the customization part and we backpace this PR to just solve the original issue and emulate the "default" behavior.

@robjtede robjtede modified the milestones: actix-web v4.4, actix-web v5.0 Jul 19, 2023
@robjtede robjtede mentioned this pull request Jul 19, 2023
5 tasks
@robjtede
Copy link
Member

I've created #3075 with the subset of changes that do not cause breakage to the public API.

@robjtede robjtede added B-semver-major breaking change requiring a major version bump and removed B-semver-minor labels May 10, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-web project: actix-web B-semver-major breaking change requiring a major version bump
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Compress middleware should not compress image/* content types
2 participants