github.com/cozy/cozy-stack@v0.0.0-20240603063001-31110fa4cae1/pkg/filetype/filetype.go (about) 1 package filetype 2 3 import ( 4 "bytes" 5 "io" 6 "mime" 7 "strings" 8 9 "github.com/cozy/cozy-stack/pkg/consts" 10 ftype "github.com/h2non/filetype" 11 ) 12 13 // DefaultType is the type used when we can't know/guess the filetype. 14 const DefaultType = "application/octet-stream" 15 16 // ByExtension calls mime.TypeByExtension, and removes optional parameters, to 17 // keep only the type and subtype. 18 // Example: text/html 19 func ByExtension(ext string) string { 20 switch ext { 21 case ".cozy-note": 22 return consts.NoteMimeType 23 case ".url": 24 return consts.ShortcutMimeType 25 } 26 mimeParts := strings.SplitN(mime.TypeByExtension(ext), ";", 2) 27 return strings.TrimSpace(mimeParts[0]) 28 } 29 30 // Match returns the mime-type (no charset) if it can guess from the first 31 // bytes, or the default content-type else. 32 func Match(buf []byte) string { 33 mimetype := DefaultType 34 if kind, err := ftype.Match(buf); err == nil { 35 mimetype = kind.MIME.Value 36 } 37 return mimetype 38 } 39 40 // FromReader takes a reader, sniffs the beginning of it, and returns the 41 // mime-type (no charset) and a new reader that's the concatenation of the 42 // bytes sniffed and the remaining reader. 43 func FromReader(r io.Reader) (string, io.Reader) { 44 var buf bytes.Buffer 45 _, err := io.Copy(&buf, io.LimitReader(r, 512)) 46 if err != nil { 47 return DefaultType, io.MultiReader(&buf, errReader{err}) 48 } 49 return Match(buf.Bytes()), io.MultiReader(&buf, r) 50 } 51 52 // errReader is an io.Reader which just returns err. 53 type errReader struct{ err error } 54 55 func (er errReader) Read([]byte) (int, error) { return 0, er.err }