Efficient serving of pre-compressed static files.
Find a file
Laurence Withers cd9c8b600e packed: add ability to load from memory, add MapAndLoad
The ability to load a packfile from memory means that it becomes easy to
use the "embed" package to embed a small packfile.

The refactor to allow loading from memory also makes it easy to add a
MapAndLoad implementation, which means the file only needs to be opened
/ mmap()ed once.
2026-06-06 10:16:40 +01:00
cmd cmd/htpacker: swap out progress bar library 2024-08-24 09:54:25 +01:00
packed packed: add ability to load from memory, add MapAndLoad 2026-06-06 10:16:40 +01:00
.gitignore Finish up the initial packserver implementation 2019-04-15 14:10:26 +01:00
go.mod Update Go version to 1.25, update golang.org/x/sys 2026-06-06 10:16:03 +01:00
go.sum Update Go version to 1.25, update golang.org/x/sys 2026-06-06 10:16:03 +01:00
handler.go Correct X-Frame-Options value sameorigin→SAMEORIGIN 2022-07-06 10:15:28 +01:00
LICENSE Add MIT licence file 2020-01-15 18:31:11 +00:00
README.md cmd/packserver: add --fallback-404 arg for Angular-style SPA support 2020-02-15 12:35:05 +00:00

HTTP resource pack server

GoDoc

A common scenario is that you have a set of static resources that you want to serve up quickly via HTTP (for example: stylesheets, WASM).

This package provides a net/http-compatible http.Handler to do so, with support for:

  • compression
    • gzip
    • brotli
    • does not yet support Transfer-Encoding, only Accept-Encoding/Content-Encoding
  • etags
  • ranges

The workflow is as follows:

  • (optional) build YAML file describing files to serve
  • run htpacker tool to produce a single .htpack file
  • create htpack.Handler pointing at .htpack file

The handler can easily be combined with middleware (http.StripPrefix etc.).

Range handling notes

Too many bugs have been found with range handling and composite ranges, so the handler only accepts a single range within the limits of the file. Anything else will be ignored.

The interaction between range handling and compression also seems a little ill-defined; as we have pre-compressed data, however, we can consistently serve the exact same byte data for compressed files.

Angular-style single-page application handling

If you wish to support an angular.js-style single page application, in which a Javascript application uses the browser's history API to create a set of virtual paths ("routes"), it is necessary to somehow intercept HTTP 404 errors being returned from the handler and instead return an HTTP 200 with an HTML document.

This can be achieved with a number of methods.

The simplest method is to tell packserver itself which resource to use instead of returning an HTTP 404. Use the command line argument --fallback-404 /index.html (or whichever named resource). The filename must match a packed resource, so it will be preceded with a /. It must exist in all packfiles being served.

If you have an nginx instance reverse proxying in front of htpack, then you can use a couple of extra directives. This is very flexible as it lets you override the resource for different routes. For example:

# prevent page loaded at "http://server.example/my-application" from
# requesting resources at "/*" when it should request them at
# "/my-application/*" instead
location = /my-application {
	return 308 /my-application/;
}

location /my-application/ {
	proxy_to http://htpack-addr:8080/;
	proxy_intercept_errors on;
	error_page 404 =200 /my-application/;
}

If you are using the handler as a library, then you may call handler.SetNotFound(filename) to select a resource to return (with HTTP 200) if a request is made for a resource that is not found. The filename must match a packed resource, so it will be preceded with a / (for example it may be "/index.html").