mirror of
https://github.com/gohugoio/hugo.git
synced 2025-09-08 23:40:40 +02:00
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
This commit is contained in:
@@ -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() {
|
||||
|
Reference in New Issue
Block a user