dana-medical-site/internal/api/media_webp.go
2026-10-14 13:33:13 +00:00

63 lines
2.1 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package api
import (
"net/http"
"os"
"path"
"path/filepath"
"strings"
)
// mediaHandler раздаёт /media/… из dir. Браузеру, который принимает WebP, вместо
// .jpg/.jpeg/.png отдаётся готовая копия «имя.jpg.webp» рядом с оригиналом, если она есть:
// пути в базе не меняются, а картинки весят в разы меньше. Копии делает
// migrations/import/make_webp.py; для новой картинки без копии отдаётся оригинал.
func mediaHandler(dir string) http.Handler {
files := http.StripPrefix("/media/", http.FileServer(noDirFS{http.Dir(dir)}))
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
switch strings.ToLower(path.Ext(r.URL.Path)) {
case ".jpg", ".jpeg", ".png":
default:
files.ServeHTTP(w, r)
return
}
w.Header().Add("Vary", "Accept")
if !strings.Contains(r.Header.Get("Accept"), "image/webp") {
files.ServeHTTP(w, r)
return
}
// path.Clean от «/…» не выпускает за пределы dir
rel := strings.TrimPrefix(path.Clean(r.URL.Path), "/media/")
f, err := os.Open(filepath.Join(dir, filepath.FromSlash(rel)) + ".webp")
if err != nil {
files.ServeHTTP(w, r)
return
}
defer f.Close()
st, err := f.Stat()
if err != nil || st.IsDir() {
files.ServeHTTP(w, r)
return
}
w.Header().Set("Content-Type", "image/webp")
http.ServeContent(w, r, "", st.ModTime(), f)
})
}
// noDirFS отдаёт только файлы: открытие каталога — «не найдено». Иначе http.FileServer
// показывает список всех загруженных файлов, включая ещё не опубликованные документы.
type noDirFS struct{ fs http.FileSystem }
func (n noDirFS) Open(name string) (http.File, error) {
f, err := n.fs.Open(name)
if err != nil {
return nil, err
}
st, err := f.Stat()
if err != nil || st.IsDir() {
f.Close()
return nil, os.ErrNotExist
}
return f, nil
}