91 lines
2.9 KiB
Go
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)
|
|
}
|