Parent directory

raw.go

1471 bytes
 1package pages
 2
 3import (
 4	"mime"
 5	"path"
 6	"strings"
 7	"unicode"
 8)
 9
10// RawMetadata describes how a raw blob may be sent without executable content.
11type RawMetadata struct {
12	ContentType        string
13	ContentDisposition string
14	Inline             bool
15}
16
17var safeMediaTypes = map[string]string{
18	".avif": "image/avif",
19	".gif":  "image/gif",
20	".jpeg": "image/jpeg",
21	".jpg":  "image/jpeg",
22	".png":  "image/png",
23	".webp": "image/webp",
24	".flac": "audio/flac",
25	".m4a":  "audio/mp4",
26	".mp3":  "audio/mpeg",
27	".ogg":  "audio/ogg",
28	".opus": "audio/opus",
29	".wav":  "audio/wav",
30	".m4v":  "video/mp4",
31	".mp4":  "video/mp4",
32	".ogv":  "video/ogg",
33	".webm": "video/webm",
34}
35
36// RawFileMetadata allows only known safe media types inline; all other files download.
37func RawFileMetadata(filename string) RawMetadata {
38	if mediaType, ok := safeMediaTypes[strings.ToLower(path.Ext(filename))]; ok {
39		return RawMetadata{ContentType: mediaType, Inline: true}
40	}
41	return RawMetadata{
42		ContentType:        "application/octet-stream",
43		ContentDisposition: mime.FormatMediaType("attachment", map[string]string{"filename": safeDownloadFilename(filename)}),
44	}
45}
46
47func safeDownloadFilename(filename string) string {
48	filename = path.Base(filename)
49	filename = strings.Map(func(char rune) rune {
50		if char == '/' || char == '\\' || unicode.IsControl(char) {
51			return -1
52		}
53		return char
54	}, filename)
55	if filename == "" || filename == "." {
56		return "download"
57	}
58	return filename
59}