-
Notifications
You must be signed in to change notification settings - Fork 0
/
mimetype.go
91 lines (75 loc) · 1.91 KB
/
mimetype.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
package pdmimetype
import (
"net/http"
"unicode/utf8"
)
type typeMatcher interface {
match(header []byte) (fileType string)
}
var types = []typeMatcher{
// 12 bytes
masked{[]byte("\x00\x00\x00\x00ftypMSNV"), []byte("000011111111"), "video/mp4"},
masked{[]byte("\x00\x00\x00\x00ftypisom"), []byte("000011111111"), "video/mp4"},
// 6 bytes
exact{[]byte("\x37\x7A\xBC\xAF\x27\x1C"), "application/7z-compressed"},
// 4 bytes
exact{[]byte("fLaC"), "audio/flac"},
exact{[]byte("OggS"), "application/ogg"},
exact{[]byte("\x1A\x45\xDF\xA3"), "video/x-matroska"},
// 3 bytes
exact{[]byte("\x49\x44\x33"), "audio/mp3"},
// 2 bytes
exact{[]byte("\xFF\xFB"), "audio/mp3"},
}
// Detect detects the content type of a file by the first bytes of the
// file
func Detect(head []byte) (mimeType string) {
// Manual magic byte detection
if mimeType == "application/octet-stream" || mimeType == "" {
for _, v := range types {
if mimeType = v.match(head); mimeType != "" {
return mimeType
}
}
}
// Try the mime type detection from the http package
mimeType = http.DetectContentType(head)
// Check if the mime type is valid UTF-8
if mimeType == "application/octet-stream" || mimeType == "" {
if utf8.Valid(head) {
mimeType = "text/plain; charset=utf-8"
}
}
// Mime type is still unknown, we fall back to the default type
if mimeType == "" {
mimeType = "application/octet-stream"
}
return mimeType
}
type exact struct {
sig []byte
typ string
}
func (e exact) match(head []byte) (contentType string) {
if string(e.sig) == string(head[:len(e.sig)]) {
return e.typ
}
return ""
}
type masked struct {
sig []byte
mask []byte
typ string
}
func (e masked) match(head []byte) (contentType string) {
if len(head) < len(e.sig) {
return ""
}
for i, v := range e.mask {
// If the mask is high and the bytes don't match the test fails
if v == '1' && e.sig[i] != head[i] {
return ""
}
}
return e.typ
}