vole
Clone
Read only, no credentials:
https://rodent.software/git/vole.git
Write over SSH with a registered key:
git clone ssh://git@0.0.0.0:2222/vole.git
A free and open-source forge that lives in your Git repo.
Compress hosted site responses too
a76b2f38cb6692f7fe88c83e4552205d398f30df · Keenan Nemetz · 12d ago · parent 306f36fc
Compress hosted site responses too The gzip middleware covered the forge UI and nothing else: server.Handler dispatches a site host to server/pages before the forge middleware runs, so every hosted site was serving raw HTML, CSS and JavaScript. A site is a static file server, which is the best case gzip has. The compressor moves from server/web to internal/compress so both surfaces share one implementation of the negotiation and header rules, with two entry points: New for the forge, which needs the writer inside its own status recorder and panic handling, and Handler for the site dispatcher. Site responses keep their ETag and Last-Modified, so revalidation is still a 304 off the blob sha; Vary: Accept-Encoding names the representation; a 304 and a 301 carry no body to compress; and a client that does not ask for gzip still gets the exact bytes and the exact Content-Length. Measured on the site path, an HTML page with repeated markup goes from 1.5 KB to 83 bytes.
server/server.go +9−1
| @@ -21,6 +21,7 @@ import ( | |||
| 21 | 21 | "github.com/rodent-software/vole/forge/pageview" | |
| 22 | 22 | "github.com/rodent-software/vole/forge/repo" | |
| 23 | 23 | "github.com/rodent-software/vole/forge/session" | |
| 24 | "github.com/rodent-software/vole/internal/compress" | ||
| 24 | 25 | "github.com/rodent-software/vole/server/githttp" | |
| 25 | 26 | "github.com/rodent-software/vole/server/pages" | |
| 26 | 27 | "github.com/rodent-software/vole/server/ssh" | |
| @@ -185,14 +186,21 @@ func New(cfg *config.Config, binPath string, log *slog.Logger) (*Server, error) | |||
| 185 | 186 | ||
| 186 | 187 | // Handler returns the HTTP surface. Site hosts are dispatched first: a request | |
| 187 | 188 | // for <repo>.<pages_domain> is a page, and everything else is the forge UI. | |
| 189 | // | ||
| 190 | // Sites are compressed here rather than inside the pages package because the | ||
| 191 | // dispatcher is the last point both surfaces pass through, and a site is a static | ||
| 192 | // file server: HTML, CSS and JavaScript, which is exactly what gzip is for. The | ||
| 193 | // forge UI does its own, inside its middleware, because the compressor has to sit | ||
| 194 | // under the status recorder there. | ||
| 188 | 195 | func (s *Server) Handler() http.Handler { | |
| 189 | 196 | forge := s.Web.Middleware(s.mux) | |
| 190 | 197 | if s.Pages == nil { | |
| 191 | 198 | return forge | |
| 192 | 199 | } | |
| 200 | sites := compress.Handler(s.Pages) | ||
| 193 | 201 | return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | |
| 194 | 202 | if _, ok := s.Pages.Host(r.Host); ok { | |
| 195 | s.Pages.ServeHTTP(w, r) | ||
| 203 | sites.ServeHTTP(w, r) | ||
| 196 | 204 | return | |
| 197 | 205 | } | |
| 198 | 206 | forge.ServeHTTP(w, r) | |