gouda/godl/godl.go
2024-09-23 22:33:10 +02:00

91 lines
2.9 KiB
Go

// Package godl provides utilities for serving files over HTTP, with MIME type
// inference and support for setting Content-Disposition headers to control
// whether files are served inline or as attachments.
package godl
import (
"mime"
"net/http"
"net/url"
"path/filepath"
"github.com/gabriel-vasile/mimetype"
)
// Infer returns the MIME type of the file specified by the given path. It
// first attempts to determine the MIME type using InferByMagic, and if
// unsuccessful, it falls back to InferByExtension.
func Infer(path string) string {
m := InferByMagic(path)
if m == "" {
return InferByExtension(path)
}
return m
}
// InferByExtension returns the MIME type of the file specified by the given
// path using the file extension, or an empty string if no match is found.
func InferByExtension(path string) string {
return mime.TypeByExtension(filepath.Ext(path))
}
// InferByMagic returns the MIME type of the file specified by the given
// path using the mimetype module, or an empty string if no match is found.
func InferByMagic(path string) string {
if m, err := mimetype.DetectFile(path); err == nil {
return m.String()
}
return ""
}
// SetContentType sets the Content-Type header for the file specified by the
// given path, inferred using the provided infer function.
func SetContentType(w http.ResponseWriter, path string, infer func(string) string) {
m := infer(path)
if m == "" {
m = "application/octet-stream"
}
w.Header().Set("Content-Type", m)
}
// SetAttachment sets the Content-Disposition header to inform the client
// that the file is an attachment, specifying the name of the file.
func SetAttachment(w http.ResponseWriter, name string) {
w.Header().Set(
"Content-Disposition",
"attachment; filename*=UTF-8''"+url.QueryEscape(name),
)
}
// ServeAttachment serves a file with the specified name and path, setting
// the Content-Type header using the provided infer function and marking it as
// an attachment by setting the Content-Disposition header.
func ServeAttachment(w http.ResponseWriter, r *http.Request, path string, name string, infer func(string) string) {
SetContentType(w, path, infer)
SetAttachment(w, name)
http.ServeFile(w, r, path)
}
// ServeDownload serves a file with the specified name and path, setting the
// Content-Type header using the provided infer function and determining
// whether to show the file inline based on the list of inline types. If the
// list is empty, all content types are treated as inline. Additionally, it
// sets the Content-Disposition header accordingly.
func ServeDownload(w http.ResponseWriter, r *http.Request, path string, name string, inlineTypes []string, infer func(string) string) {
SetContentType(w, path, infer)
inline := len(inlineTypes) == 0
for _, it := range inlineTypes {
if it == w.Header().Get("Content-Type") {
inline = true
break
}
}
if !inline {
SetAttachment(w, name)
}
http.ServeFile(w, r, path)
}