Skip to content
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

Precompressed files #156

Merged
merged 8 commits into from
Nov 15, 2021
Merged

Conversation

Nehliin
Copy link
Collaborator

@Nehliin Nehliin commented Nov 11, 2021

Motivation

Suggestion for an implementation that should fix #120.

Solution

The user specifies which types of precompression is available in the same directory as the original file by specifying precompressed_[gzip|br|deflate] to the ServeFile service. It is not required to have the compression feature enabled since no compression/decompression actually happens on the server. The ServeFile service looks for copies of the original file with the extension .gz, .bror .zz depending on the compression used/specified. If a client requests the file and doesn't support any of the precompressed variants the "normal" file will be served instead. This means it's expected that the uncompressed version of the file also exists if all clients should be able to request the file. Otherwise a 404 will be returned if the client doesn't support the compression algorithm.

@davidpdrsn davidpdrsn added this to the 0.2.0 milestone Nov 11, 2021
@Nehliin Nehliin force-pushed the precompressed-files branch 2 times, most recently from 7d2692b to b5bb0a3 Compare November 12, 2021 09:56
@Nehliin Nehliin marked this pull request as ready for review November 12, 2021 09:56
@Nehliin
Copy link
Collaborator Author

Nehliin commented Nov 12, 2021

Cleaned up a bit and added more tests and support for ServeDir so I think its ready for review now

Copy link
Member

@davidpdrsn davidpdrsn left a comment

Choose a reason for hiding this comment

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

Great work! I think it looks good as it.

I'll put this on 0.2 milestone.

@@ -74,7 +117,7 @@ impl ServeFile {
}
}

impl<R> Service<R> for ServeFile {
impl<ReqBody> Service<Request<ReqBody>> for ServeFile {
Copy link
Member

Choose a reason for hiding this comment

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

Its a shame that this required a breaking change. I think for 0.2 we should audit all services and make sure they implement Service<Request<B>> so we can make changes like this in the future.

tower-http/src/services/fs/serve_dir.rs Outdated Show resolved Hide resolved
@davidpdrsn davidpdrsn added the breaking change A PR that makes a breaking change. label Nov 12, 2021
@Nehliin
Copy link
Collaborator Author

Nehliin commented Nov 12, 2021

Thanks! I'll fix the CI as well either today or tomorrow

@davidpdrsn
Copy link
Member

There were some general CI issues which I'm fixing in #158

@Nehliin
Copy link
Collaborator Author

Nehliin commented Nov 12, 2021

Ah great, yeah the the cargo hack issue should have been there before my pr as well unless I'm missing something 🤔

async fn only_precompressed_variant_existing() {
let svc = ServeDir::new("../test-files").precompressed_gzip();

let request = Request::builder().body(Body::empty()).unwrap();
Copy link
Contributor

Choose a reason for hiding this comment

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

Should this specify the .uri to match?

}
}

pub(crate) fn to_file_extention(self) -> Option<&'static OsStr> {
Copy link
Contributor

Choose a reason for hiding this comment

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

typo: "extension"

Comment on lines 68 to 74
/// Informs the service that it should look for a precompressed (by the gzip algorithm)
/// version of _any_ file in the directory with the correct file extension that can be
/// served if the client have the correct corresponding `Accept-Encoding`.
/// (i.e `dir/foo.txt.gz` when the served directory is `dir` and the requested file is `foo.txt`)
/// If not the uncompressed version will be served instead. Note that this means
/// that both the precompressed version(s) and the uncompressed file is expected
/// to be present in the same directory.
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
/// Informs the service that it should look for a precompressed (by the gzip algorithm)
/// version of _any_ file in the directory with the correct file extension that can be
/// served if the client have the correct corresponding `Accept-Encoding`.
/// (i.e `dir/foo.txt.gz` when the served directory is `dir` and the requested file is `foo.txt`)
/// If not the uncompressed version will be served instead. Note that this means
/// that both the precompressed version(s) and the uncompressed file is expected
/// to be present in the same directory.
/// Informs the service that it should look for a precompressed gzip
/// version of _any_ file in the directory.
///
/// If the client has an `Accept-Encoding` header that allows the gzip encoding,
/// the file `dir/foo.txt.gz` will be served instead of `dir/foo.txt`.
/// If the precompressed file is not available, or the client doesn't support it,
/// the uncompressed version will be served instead.
/// Both the precompressed version and the uncompressed version are expected
/// to be present in the directory.

(ditto similar suggestions to the sibling methods)

I'm not sure where it should be mentioned about the q settings for browser preference.

@@ -7,7 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

# Unreleased

- None.
- `ServeDir` and `ServeFile`: Ability to serve precompressed files ([#156])
Copy link
Member

Choose a reason for hiding this comment

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

I think its missing a link to [#156] 🤔

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Huh? Isn't that the last part ([#156]) or do I need to do something else as well?

Copy link
Member

Choose a reason for hiding this comment

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

You need to add link for it like its done for the other changelog entries. GH doesn't pick it up automatically unfortunately.

It'll look like this otherwise:

image

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

ah right completely missed that, fixed now!

@c5soft
Copy link
Contributor

c5soft commented Nov 17, 2021

Hi there, I'm wondering if it is a design problem that ServeDir/File will fail when precompressed_gzip enabled and path/file.ext.gz not exists but path/file.ext exists. this should works without content-encoding.
In my opinion, negotiated_encoding should be determined by: 1. precompressed_variants 2.client Accept-Encoding, 3.precompressed file exists. Any one of three conditions is not statisfied will cause uncompressed file used. Multiple prcompressed type co-statisfied, we my consider br first, then gzip, the third deflate.

@Nehliin
Copy link
Collaborator Author

Nehliin commented Nov 17, 2021

Hi @c5soft if the developer has explicitly indicated that there should exist an precompressed variant I think its fair to return 404 to clients that supports the encoding (all browsers) since it would be an error on the side of the developer and it makes it easy to notice after a basic check. Otherwise the developer might think it serves precompressed files without them actually existing.

Another option would be to remove the precompressed_[gzip|br|deflate| and automatically always look for precompressed variants and fallback if they don't exist. However that wouldn't be zero cost for developers who know they don't have precompressed files. We would have to do additional system calls and checks to look for the precompressed variants in almost all cases since again, all large browsers supports the content encodings.

@davidpdrsn
Copy link
Member

if the developer has explicitly indicated that there should exist an precompressed variant I think its fair to return 404

I didn't catch that about this implementation. Not sure thats ideal since ServeDir serves any file in the directory and all subdirectories. So you'd have to precompress all files even if you're only really interested in precompressing a single file. You might also be serving images which don't benefit much from compression afaik.

@Nehliin
Copy link
Collaborator Author

Nehliin commented Nov 17, 2021

@davidpdrsn Yeah that's fair, I didn't think about the ServeDir case becoming quite inconvenient to work with if you have images etc. I can create a PR to fallback if it doesn't exist. I presume we want to change the ServeFile service then as well to keep it consistent?

@davidpdrsn
Copy link
Member

That would be great 😊 and yeah adding it to ServeFile as well would be nice.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
breaking change A PR that makes a breaking change.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Have ServeDir and ServeFile serve precompressed files
4 participants