mirror of
https://github.com/safing/portbase
synced 2025-04-21 09:49:10 +00:00
Improve mime type selection
This commit is contained in:
parent
b41b567d2a
commit
47f6eb5163
2 changed files with 56 additions and 34 deletions
formats/dsd
|
@ -95,10 +95,10 @@ func DumpToHTTPResponse(w http.ResponseWriter, r *http.Request, t interface{}) e
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// MimeLoad loads the given data into the interface based on the given mime type.
|
// MimeLoad loads the given data into the interface based on the given mime type accept header.
|
||||||
func MimeLoad(data []byte, mimeType string, t interface{}) (format uint8, err error) {
|
func MimeLoad(data []byte, accept string, t interface{}) (format uint8, err error) {
|
||||||
// Find format.
|
// Find format.
|
||||||
format = FormatFromMime(mimeType)
|
format = FormatFromAccept(accept)
|
||||||
if format == 0 {
|
if format == 0 {
|
||||||
return 0, ErrIncompatibleFormat
|
return 0, ErrIncompatibleFormat
|
||||||
}
|
}
|
||||||
|
@ -111,40 +111,53 @@ func MimeLoad(data []byte, mimeType string, t interface{}) (format uint8, err er
|
||||||
// MimeDump dumps the given interface based on the given mime type accept header.
|
// MimeDump dumps the given interface based on the given mime type accept header.
|
||||||
func MimeDump(t any, accept string) (data []byte, mimeType string, format uint8, err error) {
|
func MimeDump(t any, accept string) (data []byte, mimeType string, format uint8, err error) {
|
||||||
// Find format.
|
// Find format.
|
||||||
accept = extractMimeType(accept)
|
format = FormatFromAccept(accept)
|
||||||
switch accept {
|
if format == AUTO {
|
||||||
case "", "*":
|
return nil, "", 0, ErrIncompatibleFormat
|
||||||
format = DefaultSerializationFormat
|
|
||||||
default:
|
|
||||||
format = MimeTypeToFormat[accept]
|
|
||||||
if format == 0 {
|
|
||||||
return nil, "", 0, ErrIncompatibleFormat
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
mimeType = FormatToMimeType[format]
|
|
||||||
|
|
||||||
// Serialize and return.
|
// Serialize and return.
|
||||||
data, err = dumpWithoutIdentifier(t, format, "")
|
data, err = dumpWithoutIdentifier(t, format, "")
|
||||||
return data, mimeType, format, err
|
return data, mimeType, format, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// FormatFromMime returns the format for the given mime type.
|
// FormatFromAccept returns the format for the given accept definition.
|
||||||
// Will return AUTO format for unsupported or unrecognized mime types.
|
// The accept parameter matches the format of the HTTP Accept header.
|
||||||
func FormatFromMime(mimeType string) (format uint8) {
|
// Special cases, in this order:
|
||||||
return MimeTypeToFormat[extractMimeType(mimeType)]
|
// - If accept is an empty string: returns default serialization format.
|
||||||
}
|
// - If accept contains no supported format, but a wildcard: returns default serialization format.
|
||||||
|
// - If accept contains no supported format, and no wildcard: returns AUTO format.
|
||||||
|
func FormatFromAccept(accept string) (format uint8) {
|
||||||
|
if accept == "" {
|
||||||
|
return DefaultSerializationFormat
|
||||||
|
}
|
||||||
|
|
||||||
func extractMimeType(mimeType string) string {
|
var foundWildcard bool
|
||||||
if strings.Contains(mimeType, ",") {
|
for _, mimeType := range strings.Split(accept, ",") {
|
||||||
mimeType, _, _ = strings.Cut(mimeType, ",")
|
// Clean mime type.
|
||||||
}
|
mimeType = strings.TrimSpace(mimeType)
|
||||||
if strings.Contains(mimeType, ";") {
|
|
||||||
mimeType, _, _ = strings.Cut(mimeType, ";")
|
mimeType, _, _ = strings.Cut(mimeType, ";")
|
||||||
|
if strings.Contains(mimeType, "/") {
|
||||||
|
_, mimeType, _ = strings.Cut(mimeType, "/")
|
||||||
|
}
|
||||||
|
mimeType = strings.ToLower(mimeType)
|
||||||
|
|
||||||
|
// Check if mime type is supported.
|
||||||
|
format, ok := MimeTypeToFormat[mimeType]
|
||||||
|
if ok {
|
||||||
|
return format
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return default mime type as fallback if any mimetype is okay.
|
||||||
|
if mimeType == "*" {
|
||||||
|
foundWildcard = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if strings.Contains(mimeType, "/") {
|
|
||||||
_, mimeType, _ = strings.Cut(mimeType, "/")
|
if foundWildcard {
|
||||||
|
return DefaultSerializationFormat
|
||||||
}
|
}
|
||||||
return strings.ToLower(mimeType)
|
return AUTO
|
||||||
}
|
}
|
||||||
|
|
||||||
// Format and MimeType mappings.
|
// Format and MimeType mappings.
|
||||||
|
|
|
@ -23,14 +23,23 @@ func TestMimeTypes(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test assumptions.
|
// Test assumptions.
|
||||||
for mimeType, mimeTypeCleaned := range map[string]string{
|
for accept, format := range map[string]uint8{
|
||||||
"application/xml, image/webp": "xml",
|
"application/json, image/webp": JSON,
|
||||||
"application/xml;q=0.9, image/webp": "xml",
|
"image/webp, application/json": JSON,
|
||||||
"*": "*",
|
"application/json;q=0.9, image/webp": JSON,
|
||||||
"*/*": "*",
|
"*": DefaultSerializationFormat,
|
||||||
"text/yAMl": "yaml",
|
"*/*": DefaultSerializationFormat,
|
||||||
|
"text/yAMl": YAML,
|
||||||
|
" * , yaml ": YAML,
|
||||||
|
"yaml;charset ,*": YAML,
|
||||||
|
"xml,*": DefaultSerializationFormat,
|
||||||
|
"text/xml, text/other": AUTO,
|
||||||
|
"text/*": DefaultSerializationFormat,
|
||||||
|
"yaml ;charset": AUTO, // Invalid mimetype format.
|
||||||
|
"": DefaultSerializationFormat,
|
||||||
|
"x": AUTO,
|
||||||
} {
|
} {
|
||||||
cleaned := extractMimeType(mimeType)
|
derivedFormat := FormatFromAccept(accept)
|
||||||
assert.Equal(t, mimeTypeCleaned, cleaned, "assumption for %q should hold", mimeType)
|
assert.Equal(t, format, derivedFormat, "assumption for %q should hold", accept)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue