Clean up wrong vanity rules
This commit is contained in:
@@ -6,6 +6,7 @@ import (
|
||||
"fmt"
|
||||
"html/template"
|
||||
"io"
|
||||
"io/fs"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"strings"
|
||||
@@ -32,6 +33,10 @@ type Server struct {
|
||||
authLimiter *limiter
|
||||
slots chan struct{} // bounds uploads in flight
|
||||
|
||||
// favicon is the name of the embedded icon, or "" when this build has
|
||||
// none. Resolved once: the assets cannot change while the process runs.
|
||||
favicon string
|
||||
|
||||
now func() time.Time // swappable in tests
|
||||
}
|
||||
|
||||
@@ -50,6 +55,7 @@ func New(cfg *config.Config, st *store.Store, tokens *auth.File, log *slog.Logge
|
||||
authLimiter: newLimiter(120, 20),
|
||||
slots: make(chan struct{}, cfg.MaxConcurrent),
|
||||
now: time.Now,
|
||||
favicon: faviconFor(web.Static()),
|
||||
}
|
||||
s.handler = s.routes()
|
||||
return s, nil
|
||||
@@ -70,6 +76,9 @@ func (s *Server) routes() http.Handler {
|
||||
mux.HandleFunc("POST /login", s.handleLogin)
|
||||
mux.HandleFunc("POST /logout", s.handleLogout)
|
||||
mux.Handle("GET /static/", http.StripPrefix("/static/", s.staticHandler()))
|
||||
if s.favicon != "" {
|
||||
mux.HandleFunc("GET /favicon.ico", s.handleFavicon)
|
||||
}
|
||||
mux.HandleFunc("/", s.handleNotFound)
|
||||
|
||||
var h http.Handler = mux
|
||||
@@ -92,6 +101,29 @@ func (s *Server) routes() http.Handler {
|
||||
|
||||
// staticHandler serves the embedded assets with a long, immutable-ish cache
|
||||
// window kept short enough that an edit shows up without a cache-buster.
|
||||
// faviconFor names the icon to serve, or "" when the build has none. The file
|
||||
// is optional on purpose: none is committed, and dropping one into web/static
|
||||
// before building is the whole of the installation procedure.
|
||||
func faviconFor(fsys fs.FS) string {
|
||||
// A .png is preferred where both exist; every browser in service reads it,
|
||||
// and .ico survives only as the name the root request asks for.
|
||||
for _, name := range []string{"favicon.png", "favicon.ico"} {
|
||||
if f, err := fsys.Open(name); err == nil {
|
||||
f.Close()
|
||||
return name
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// handleFavicon answers the root request browsers make on their own, whichever
|
||||
// of the two names the build supplied: a .png served here is still a .png, and
|
||||
// the Content-Type says so.
|
||||
func (s *Server) handleFavicon(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Cache-Control", "public, max-age=300")
|
||||
http.ServeFileFS(w, r, web.Static(), s.favicon)
|
||||
}
|
||||
|
||||
func (s *Server) staticHandler() http.Handler {
|
||||
fileServer := http.FileServerFS(web.Static())
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -196,6 +228,10 @@ type page struct {
|
||||
User string
|
||||
Admin bool
|
||||
|
||||
// Favicon is the icon's URL, empty when the build shipped none, in which
|
||||
// case the markup carries no link rather than one that 404s.
|
||||
Favicon string
|
||||
|
||||
// Wide widens the page for content that is a table rather than a form.
|
||||
// The reading measure that suits the upload page is far too narrow for a
|
||||
// listing, which otherwise ends up behind a horizontal scrollbar.
|
||||
@@ -206,6 +242,9 @@ type page struct {
|
||||
// who is logged in and offer only the links they can use.
|
||||
func (s *Server) page(r *http.Request, title string, script bool) page {
|
||||
p := page{Base: s.cfg.BasePath, Title: title, Script: script}
|
||||
if s.favicon != "" {
|
||||
p.Favicon = s.cfg.BasePath + "static/" + s.favicon
|
||||
}
|
||||
if lim, err := s.limitsFor(r, cookieCredential(r)); err == nil {
|
||||
p.User, p.Admin = lim.Name, lim.Admin
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user