summaryrefslogtreecommitdiffstats
path: root/media/mediaType.go
diff options
context:
space:
mode:
authorBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>2021-12-16 15:12:13 +0100
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>2021-12-17 09:50:28 +0100
commit44954497bcb2d6d589b9340a43323663061c7b42 (patch)
tree0d0d06b11e462ccff1a908c2b1c4dfd039b82787 /media/mediaType.go
parent22ef5da20d1685dfe6aff3bd9364c9b1f1d0d8f8 (diff)
Always use content to resolve content type in resources.GetRemote
This is a security hardening measure; don't trust the URL extension or any `Content-Type`/`Content-Disposition` header on its own, always look at the file content using Go's `http.DetectContentType`. This commit also adds ttf and otf media type definitions to Hugo. Fixes #9302 Fixes #9301
Diffstat (limited to 'media/mediaType.go')
-rw-r--r--media/mediaType.go58
1 files changed, 58 insertions, 0 deletions
diff --git a/media/mediaType.go b/media/mediaType.go
index eec7a27a8..0bdeb6db7 100644
--- a/media/mediaType.go
+++ b/media/mediaType.go
@@ -17,6 +17,7 @@ import (
"encoding/json"
"errors"
"fmt"
+ "net/http"
"sort"
"strings"
@@ -60,6 +61,42 @@ type SuffixInfo struct {
FullSuffix string `json:"fullSuffix"`
}
+// FromContent resolve the Type primarily using http.DetectContentType.
+// If http.DetectContentType resolves to application/octet-stream, a zero Type is returned.
+// If http.DetectContentType resolves to text/plain or application/xml, we try to get more specific using types and ext.
+func FromContent(types Types, ext string, content []byte) Type {
+ ext = strings.TrimPrefix(ext, ".")
+ t := strings.Split(http.DetectContentType(content), ";")[0]
+ var m Type
+ if t == "application/octet-stream" {
+ return m
+ }
+
+ var found bool
+ m, found = types.GetByType(t)
+ if !found {
+ if t == "text/xml" {
+ // This is how it's configured in Hugo by default.
+ m, found = types.GetByType("application/xml")
+ }
+ }
+
+ if !found || ext == "" {
+ return m
+ }
+
+ if m.Type() == "text/plain" || m.Type() == "application/xml" {
+ // http.DetectContentType isn't brilliant when it comes to common text formats, so we need to do better.
+ // For now we say that if it's detected to be a text format and the extension/content type in header reports
+ // it to be a text format, then we use that.
+ mm, _, found := types.GetFirstBySuffix(ext)
+ if found && mm.IsText() {
+ return mm
+ }
+ }
+ return m
+}
+
// FromStringAndExt creates a Type from a MIME string and a given extension.
func FromStringAndExt(t, ext string) (Type, error) {
tp, err := fromString(t)
@@ -122,6 +159,21 @@ func (m Type) Suffixes() []string {
return strings.Split(m.suffixesCSV, ",")
}
+// IsText returns whether this Type is a text format.
+// Note that this may currently return false negatives.
+// TODO(bep) improve
+func (m Type) IsText() bool {
+ if m.MainType == "text" {
+ return true
+ }
+ switch m.SubType {
+ case "javascript", "json", "rss", "xml", "svg", TOMLType.SubType, YAMLType.SubType:
+ return true
+
+ }
+ return false
+}
+
func (m *Type) init() {
m.FirstSuffix.FullSuffix = ""
m.FirstSuffix.Suffix = ""
@@ -183,6 +235,10 @@ var (
BMPType = newMediaType("image", "bmp", []string{"bmp"})
WEBPType = newMediaType("image", "webp", []string{"webp"})
+ // Common font types
+ TrueTypeFontType = newMediaType("font", "ttf", []string{"ttf"})
+ OpenTypeFontType = newMediaType("font", "otf", []string{"otf"})
+
// Common video types
AVIType = newMediaType("video", "x-msvideo", []string{"avi"})
MPEGType = newMediaType("video", "mpeg", []string{"mpg", "mpeg"})
@@ -224,6 +280,8 @@ var DefaultTypes = Types{
OGGType,
WEBMType,
GPPType,
+ OpenTypeFontType,
+ TrueTypeFontType,
}
func init() {