26 releases (9 breaking)

0.11.0 Oct 12, 2024
0.10.1 Aug 9, 2024
0.9.2 Jul 14, 2024
0.4.3 Mar 31, 2024

#426 in HTTP server

32 downloads per month

MIT license

85KB
2K SLoC

zip_static_handler  LICENSE crates.io Version Documentation Rust 1.75

HTTP handler implementation for serving static content from a zip archive.

Handler conventions

The conventions derive from a position that can be controversial.

Urls for page documents should not include the file extension, and they should not have a trailing slash.

  • /about rather than /about/, /about.html, /about.php or /about.md.
  • The technical choice of whether /about points to an html file or a directory index should be transparent.

Derived conventions:

  • HTML files are served without the .html prefix.

  • There's no directory index except for the root

    /index.html is served as http(s)://domain.tld

The decision to remove trailing slashes is incompatible with directory indices because in an index file, you expect relative links to refer to the same directory. However, without the trailing slash, they would refer to the parent directory instead.

(Pre)compression

Compressible content types can be pre-compressed by including the compressed version of the file in the zip archive. Only brotli compression is supported.

The compressed file should be in the same directory as the original file, and have the same name with an additional .br suffix. (about.html and about.html.br).

The uncompressed file should also be present in the archive. It is used to compute the Etag.

Pre-compressed files are not checked. They are not decompressed to make sure that they match the content of the uncompressed file.

If a pre-compressed file is missing for a compressible content-type, the compressed version is computed during the creation of the Handler instance. This means that you do not have to include pre-compressed files in the zip archive, but the consequence is a substantial increase in time and cpu usage at the creation of the Handler instance.

Note that most browsers only support brotli compression with a secure context (https or localhost).

Usage

The only argument that the builder requires is the zip archive content as bytes.

let zip_bytes: & [u8] = download_zip();
let handler = Handler::builder()
.with_zip(zip_bytes)
.try_build() ?;

There are helper functions to download a zip archive from a github repository (by branch, tag or commit hash).

You can specify a prefix both for the path and for the zip content. If the zip is the export of a github repository for instance, you probably want to get rid of the repositiory-${branch_or_tag_or_commit_hash}/ prefix.

let zip_bytes = download( & zip_download_branch_url(
"programingjd",
"about.programingjd.me",
"main",
))
.await?;
let handler = Handler::builder()
.with_zip_prefix("about.programingjd.me-main/")
.with_path_prefix("about")
.with_zip(zip_bytes)
.try_build() ?;

If you are creating a new handler after each repository update, you can provide the previous handler for diffing.
This is particularly useful when the content is not pre-compressed and you let the handler take care of the compression. All the unchanged files that need to be compressed will be copied from the old handler rather than compressed again.

let handler = Handler::builder()
.with_zip_prefix("about.programingjd.me-main/")
.with_zip(zip_bytes)
.with_diff( & previous_handler)
.try_build() ?;

Features

You can choose the implementation of HTTP request and response that you need by enabling the appropriate feature:

Examples

There are examples for the different http implementations that can be enabled with the matching feature.

The hyper.rs example shows how to customize which file types are accepted and which headers are set on the responses.

The axum.rs example shows how to add tracing.

The auto_update.rs example shows how to add a webhook that updates the handler by downloading a new version of the zip archive and rebuilding the handler from that new zip archive.

Dependencies

~8–41MB
~805K SLoC