1 // Copyright 2010 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
5 // Package mime implements parts of the MIME spec.
15 mimeLock sync
.RWMutex
// guards following 3 maps
16 mimeTypes
map[string]string // ".Z" => "application/x-compress"
17 mimeTypesLower
map[string]string // ".z" => "application/x-compress"
19 // extensions maps from MIME type to list of lowercase file
20 // extensions: "image/jpeg" => [".jpg", ".jpeg"]
21 extensions
map[string][]string
24 // setMimeTypes is used by initMime's non-test path, and by tests.
25 // The two maps must not be the same, or nil.
26 func setMimeTypes(lowerExt
, mixExt
map[string]string) {
27 if lowerExt
== nil || mixExt
== nil {
30 mimeTypesLower
= lowerExt
32 extensions
= invert(lowerExt
)
35 var builtinTypesLower
= map[string]string{
36 ".css": "text/css; charset=utf-8",
38 ".htm": "text/html; charset=utf-8",
39 ".html": "text/html; charset=utf-8",
41 ".js": "application/x-javascript",
42 ".pdf": "application/pdf",
44 ".svg": "image/svg+xml",
45 ".xml": "text/xml; charset=utf-8",
48 func clone(m
map[string]string) map[string]string {
49 m2
:= make(map[string]string, len(m
))
52 if strings
.ToLower(k
) != k
{
53 panic("keys in builtinTypesLower must be lowercase")
59 func invert(m
map[string]string) map[string][]string {
60 m2
:= make(map[string][]string, len(m
))
62 justType
, _
, err
:= ParseMediaType(v
)
66 m2
[justType
] = append(m2
[justType
], k
)
71 var once sync
.Once
// guards initMime
73 var testInitMime
, osInitMime
func()
76 if fn
:= testInitMime
; fn
!= nil {
79 setMimeTypes(builtinTypesLower
, clone(builtinTypesLower
))
84 // TypeByExtension returns the MIME type associated with the file extension ext.
85 // The extension ext should begin with a leading dot, as in ".html".
86 // When ext has no associated type, TypeByExtension returns "".
88 // Extensions are looked up first case-sensitively, then case-insensitively.
90 // The built-in table is small but on unix it is augmented by the local
91 // system's mime.types file(s) if available under one or more of these
95 // /etc/apache2/mime.types
96 // /etc/apache/mime.types
98 // On Windows, MIME types are extracted from the registry.
100 // Text types have the charset parameter set to "utf-8" by default.
101 func TypeByExtension(ext
string) string {
104 defer mimeLock
.RUnlock()
106 // Case-sensitive lookup.
107 if v
:= mimeTypes
[ext
]; v
!= "" {
111 // Case-insensitive lookup.
112 // Optimistically assume a short ASCII extension and be
113 // allocation-free in that case.
116 const utf8RuneSelf
= 0x80 // from utf8 package, but not importing it.
117 for i
:= 0; i
< len(ext
); i
++ {
119 if c
>= utf8RuneSelf
{
121 return mimeTypesLower
[strings
.ToLower(ext
)]
123 if 'A' <= c
&& c
<= 'Z' {
124 lower
= append(lower
, c
+('a'-'A'))
126 lower
= append(lower
, c
)
129 // The conversion from []byte to string doesn't allocate in
131 return mimeTypesLower
[string(lower
)]
134 // ExtensionsByType returns the extensions known to be associated with the MIME
135 // type typ. The returned extensions will each begin with a leading dot, as in
136 // ".html". When typ has no associated extensions, ExtensionsByType returns an
138 func ExtensionsByType(typ
string) ([]string, error
) {
139 justType
, _
, err
:= ParseMediaType(typ
)
146 defer mimeLock
.RUnlock()
147 s
, ok
:= extensions
[justType
]
151 return append([]string{}, s
...), nil
154 // AddExtensionType sets the MIME type associated with
155 // the extension ext to typ. The extension should begin with
156 // a leading dot, as in ".html".
157 func AddExtensionType(ext
, typ
string) error
{
158 if !strings
.HasPrefix(ext
, ".") {
159 return fmt
.Errorf("mime: extension %q missing leading dot", ext
)
162 return setExtensionType(ext
, typ
)
165 func setExtensionType(extension
, mimeType
string) error
{
166 justType
, param
, err
:= ParseMediaType(mimeType
)
170 if strings
.HasPrefix(mimeType
, "text/") && param
["charset"] == "" {
171 param
["charset"] = "utf-8"
172 mimeType
= FormatMediaType(mimeType
, param
)
174 extLower
:= strings
.ToLower(extension
)
177 defer mimeLock
.Unlock()
178 mimeTypes
[extension
] = mimeType
179 mimeTypesLower
[extLower
] = mimeType
180 for _
, v
:= range extensions
[justType
] {
185 extensions
[justType
] = append(extensions
[justType
], extLower
)