A Rust Tower Service that serves files from a Zip file. The Zip file can either be opened as a file, or embedded in the binary using include_bytes!
Go to file
Elf M. Sternberg 2c516fec96 Updating the Readme and License files. 2026-06-06 13:25:57 -07:00
demo Well, it's serving 'I know it exists, but I can't show it to you.' 2026-05-18 17:33:07 -07:00
serve_zip It lives! 2026-06-06 12:30:13 -07:00
.gitignore Hey, some tests are passing. I can open a zip file and check it for validity, presence, file size, and kind. 2026-05-10 12:10:49 -07:00
Cargo.lock Well, it's serving 'I know it exists, but I can't show it to you.' 2026-05-18 17:33:07 -07:00
Cargo.toml Just following along in the textbook for now. 2026-05-10 07:45:30 -07:00
LICENSE.md Updating the Readme and License files. 2026-06-06 13:25:57 -07:00
README.md Updating the Readme and License files. 2026-06-06 13:25:57 -07:00
rustfmt.toml Just got axum up and running. Spent waaaay too long wrestling with rustic and rustfmt to get it to stop throwing errors, only to realize that the actual problem was my copy of rustfmt being waaaay out of date. With that fixed, the problem went away. 2026-05-10 08:33:42 -07:00

README.md

tower-http-servezip

ServeZip is a Rust Tower leaf service that serves files from a given Zip file. The Zip file can either be specified by a Pathbuf or a static &[u8]; the latter is intended to allow you to embed your Zip file directly into the binary, creating a complete standalone solution for a deployable web service. You just need to supply the logic.

Usage

The demo folder contains a somewhat complete implementation, including a demo zip file. TODO Full indexing is not currently implemented. The demo can be started via:

cargo run -p demo -- --zip demo/assets/demo.zip

Valid targets are: http://localhost:8001/index.html, hello.txt, and docs/just-a-file.txt. These demonstrate the basics of mime-types, content-length, and file lookup. Any other file should return a simple 404.

Internals

Interally, this is a mess. It was a project-based learning exercise, and like so much of my career now I'm not sure I could reimplement it without the book open and the lots of example code.

I'm mostly unhappy with the fact that I have to make a copy of whatever stream I'm sending out over the wire, rather than pulling it sequentially from the Zip file while it's decompressing. This is mostly intended to supply a PWA and its back-end logic in a single package; it shouldn't be doing work that often, but it still annoys me that I have to do it more than once while (briefly) wasting memory. I wish I understond Rust well enough to say "Either let me keep wasting the memory and keep the performance, or let me take the performance hit without wasting the memory."

But I'm not that good at Rust quite yet.

Lessons learned

There's a lot going on here, and I'm still not entirely thrilled with how it went down. I am proud of figuring out how to use the NewType pattern to create an implementation of ServeZip that works with Arc[u8], which is the data type I pass around containing the compresed data. Reading ServeDir's source code opened my eyes to a lot of the little bits, like separating the Config, the Builder, the Service; I have some old habits about keeping everything really close at hand, but Rust makes the implentation so smooth and efficient that I'm really starting to appreciate how it works.

This implementation just unpacks the Zip file every time. I was hoping for something smarter, maybe a way to just keep separate ZipCursors alive and re-usable, but for now this will have to do. It's not bad, it just feels like there's a lot of Rust to learn before it's much more idiomatic.

Huge shoutout to @bearcave [Bearcove]] for the sans-io implementation of Zip in Rust. I learned a lot about sans-io in the process, even if I didn't end up using much of it this time.

Todo

  • Implement full indexing
  • Implement ServeDir's use of http::body, instead of axum
  • Read ServeDir much more closely in order to understand what it's doing internally; all the security and safety issues, plus performance
  • Reduce the amount of copying. Oy, the copying
  • Put an upper limit on Zip size, configurable from the command line
  • Provide a build.rs file in the demo to show how include_bytes! works

License

Tower-http-servezip is Copyright Elf M. Sternberg (c) 2026, and licensed under the original MIT License. A copy of the license file is included in the root folder.

An all-human effort.

Every last line of this code I typed myself. No AI-provided code included. I wouldn't have learned anything otherwise. Just sayin'.