Copyright 2010 The Go Authors. All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
Package mime implements parts of the MIME spec.
package mime

import (
	
	
	
	
)

var (
	mimeTypes      sync.Map // map[string]string; ".Z" => "application/x-compress"
	mimeTypesLower sync.Map // map[string]string; ".z" => "application/x-compress"
extensions maps from MIME type to list of lowercase file extensions: "image/jpeg" => [".jpg", ".jpeg"]
	extensionsMu sync.Mutex // Guards stores (but not loads) on extensions.
	extensions   sync.Map   // map[string][]string; slice values are append-only.
)

func ( *sync.Map) {
	.Range(func(,  interface{}) bool {
		.Delete()
		return true
	})
}
setMimeTypes is used by initMime's non-test path, and by tests.
func (,  map[string]string) {
	clearSyncMap(&mimeTypes)
	clearSyncMap(&mimeTypesLower)
	clearSyncMap(&extensions)

	for ,  := range  {
		mimeTypesLower.Store(, )
	}
	for ,  := range  {
		mimeTypes.Store(, )
	}

	extensionsMu.Lock()
	defer extensionsMu.Unlock()
	for ,  := range  {
		, ,  := ParseMediaType()
		if  != nil {
			panic()
		}
		var  []string
		if ,  := extensions.Load();  {
			 = .([]string)
		}
		extensions.Store(, append(, ))
	}
}

var builtinTypesLower = map[string]string{
	".css":  "text/css; charset=utf-8",
	".gif":  "image/gif",
	".htm":  "text/html; charset=utf-8",
	".html": "text/html; charset=utf-8",
	".jpeg": "image/jpeg",
	".jpg":  "image/jpeg",
	".js":   "text/javascript; charset=utf-8",
	".json": "application/json",
	".mjs":  "text/javascript; charset=utf-8",
	".pdf":  "application/pdf",
	".png":  "image/png",
	".svg":  "image/svg+xml",
	".wasm": "application/wasm",
	".webp": "image/webp",
	".xml":  "text/xml; charset=utf-8",
}

var once sync.Once // guards initMime

var testInitMime, osInitMime func()

func () {
	if  := testInitMime;  != nil {
		()
	} else {
		setMimeTypes(builtinTypesLower, builtinTypesLower)
		osInitMime()
	}
}
TypeByExtension returns the MIME type associated with the file extension ext. The extension ext should begin with a leading dot, as in ".html". When ext has no associated type, TypeByExtension returns "". Extensions are looked up first case-sensitively, then case-insensitively. The built-in table is small but on unix it is augmented by the local system's mime.types file(s) if available under one or more of these names: /etc/mime.types /etc/apache2/mime.types /etc/apache/mime.types On Windows, MIME types are extracted from the registry. Text types have the charset parameter set to "utf-8" by default.
Case-sensitive lookup.
	if ,  := mimeTypes.Load();  {
		return .(string)
	}
Case-insensitive lookup. Optimistically assume a short ASCII extension and be allocation-free in that case.
	var  [10]byte
	 := [:0]
	const  = 0x80 // from utf8 package, but not importing it.
	for  := 0;  < len(); ++ {
		 := []
Slow path.
			,  := mimeTypesLower.Load(strings.ToLower())
			,  := .(string)
			return 
		}
		if 'A' <=  &&  <= 'Z' {
			 = append(, +('a'-'A'))
		} else {
			 = append(, )
		}
	}
	,  := mimeTypesLower.Load(string())
	,  := .(string)
	return 
}
ExtensionsByType returns the extensions known to be associated with the MIME type typ. The returned extensions will each begin with a leading dot, as in ".html". When typ has no associated extensions, ExtensionsByType returns an nil slice.
func ( string) ([]string, error) {
	, ,  := ParseMediaType()
	if  != nil {
		return nil, 
	}

	once.Do(initMime)
	,  := extensions.Load()
	if ! {
		return nil, nil
	}
	 := append([]string(nil), .([]string)...)
	sort.Strings()
	return , nil
}
AddExtensionType sets the MIME type associated with the extension ext to typ. The extension should begin with a leading dot, as in ".html".
func (,  string) error {
	if !strings.HasPrefix(, ".") {
		return fmt.Errorf("mime: extension %q missing leading dot", )
	}
	once.Do(initMime)
	return setExtensionType(, )
}

func (,  string) error {
	, ,  := ParseMediaType()
	if  != nil {
		return 
	}
	if strings.HasPrefix(, "text/") && ["charset"] == "" {
		["charset"] = "utf-8"
		 = FormatMediaType(, )
	}
	 := strings.ToLower()

	mimeTypes.Store(, )
	mimeTypesLower.Store(, )

	extensionsMu.Lock()
	defer extensionsMu.Unlock()
	var  []string
	if ,  := extensions.Load();  {
		 = .([]string)
	}
	for ,  := range  {
		if  ==  {
			return nil
		}
	}
	extensions.Store(, append(, ))
	return nil