package rest
import "strings"
// Enumeration of well-known content-types
const (
ContentTypeApplicationJSON = "application/json"
)
// ContentType defines a media type and is composed of a type, a subtype (and
// optional suffix), and optional parameters.
type ContentType struct {
Type string
Subtype string // including tree
Suffix string
Parameters map[string]string
}
// ParseContentType splits a content-type string into its parts.
//
// top-level type name / subtype name [ ; parameters ]
// top-level type name / [ tree. ] subtype name [ +suffix ] [ ; parameters ]
func ParseContentType(s string) ContentType {
ct := ContentType{}
// Top-level type name
parts := strings.SplitN(s, "/", 2) // required
if len(parts) != 2 {
return ct
}
if parts[1] == "" {
return ct
}
ct.Type = strings.TrimSpace(parts[0])
// Subtype name
sParts := strings.SplitN(parts[1], ";", -1) // optional
if len(sParts) == 0 {
return ct
}
if sParts[0] == "" {
return ct
}
ssParts := strings.SplitN(sParts[0], "+", 2) // optional
if len(ssParts) == 0 {
return ct
}
if ssParts[0] == "" {
return ct
}
ct.Subtype = strings.TrimSpace(ssParts[0])
// Optional suffix
if len(ssParts) == 2 {
ct.Suffix = strings.TrimSpace(ssParts[1])
}
// Optional parameters
params := map[string]string{}
for _, param := range sParts[1:] {
pParts := strings.SplitN(param, "=", 2)
if len(pParts) == 2 {
key := strings.TrimSpace(pParts[0])
params[key] = strings.TrimSpace(pParts[1])
} else if len(pParts) == 1 {
key := strings.TrimSpace(pParts[0])
params[key] = ""
}
}
if len(params) > 0 {
ct.Parameters = params
}
return ct
}