github.com/ccccaoqing/test@v0.0.0-20220510085219-3985d23445c0/src/mime/type.go (about) 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. 4 5 // Package mime implements parts of the MIME spec. 6 package mime 7 8 import ( 9 "fmt" 10 "strings" 11 "sync" 12 ) 13 14 var ( 15 mimeLock sync.RWMutex 16 mimeTypesLower = map[string]string{ 17 ".css": "text/css; charset=utf-8", 18 ".gif": "image/gif", 19 ".htm": "text/html; charset=utf-8", 20 ".html": "text/html; charset=utf-8", 21 ".jpg": "image/jpeg", 22 ".js": "application/x-javascript", 23 ".pdf": "application/pdf", 24 ".png": "image/png", 25 ".xml": "text/xml; charset=utf-8", 26 } 27 mimeTypes = clone(mimeTypesLower) 28 ) 29 30 func clone(m map[string]string) map[string]string { 31 m2 := make(map[string]string, len(m)) 32 for k, v := range m { 33 m2[k] = v 34 if strings.ToLower(k) != k { 35 panic("keys in mimeTypesLower must be lowercase") 36 } 37 } 38 return m2 39 } 40 41 var once sync.Once // guards initMime 42 43 // TypeByExtension returns the MIME type associated with the file extension ext. 44 // The extension ext should begin with a leading dot, as in ".html". 45 // When ext has no associated type, TypeByExtension returns "". 46 // 47 // Extensions are looked up first case-sensitively, then case-insensitively. 48 // 49 // The built-in table is small but on unix it is augmented by the local 50 // system's mime.types file(s) if available under one or more of these 51 // names: 52 // 53 // /etc/mime.types 54 // /etc/apache2/mime.types 55 // /etc/apache/mime.types 56 // 57 // On Windows, MIME types are extracted from the registry. 58 // 59 // Text types have the charset parameter set to "utf-8" by default. 60 func TypeByExtension(ext string) string { 61 once.Do(initMime) 62 mimeLock.RLock() 63 defer mimeLock.RUnlock() 64 65 // Case-sensitive lookup. 66 v := mimeTypes[ext] 67 if v != "" { 68 return v 69 } 70 71 // Case-insensitive lookup. 72 // Optimistically assume a short ASCII extension and be 73 // allocation-free in that case. 74 var buf [10]byte 75 lower := buf[:0] 76 const utf8RuneSelf = 0x80 // from utf8 package, but not importing it. 77 for i := 0; i < len(ext); i++ { 78 c := ext[i] 79 if c >= utf8RuneSelf { 80 // Slow path. 81 return mimeTypesLower[strings.ToLower(ext)] 82 } 83 if 'A' <= c && c <= 'Z' { 84 lower = append(lower, c+('a'-'A')) 85 } else { 86 lower = append(lower, c) 87 } 88 } 89 // The conversion from []byte to string doesn't allocate in 90 // a map lookup. 91 return mimeTypesLower[string(lower)] 92 } 93 94 // AddExtensionType sets the MIME type associated with 95 // the extension ext to typ. The extension should begin with 96 // a leading dot, as in ".html". 97 func AddExtensionType(ext, typ string) error { 98 if !strings.HasPrefix(ext, ".") { 99 return fmt.Errorf(`mime: extension %q misses dot`, ext) 100 } 101 once.Do(initMime) 102 return setExtensionType(ext, typ) 103 } 104 105 func setExtensionType(extension, mimeType string) error { 106 _, param, err := ParseMediaType(mimeType) 107 if err != nil { 108 return err 109 } 110 if strings.HasPrefix(mimeType, "text/") && param["charset"] == "" { 111 param["charset"] = "utf-8" 112 mimeType = FormatMediaType(mimeType, param) 113 } 114 extLower := strings.ToLower(extension) 115 116 mimeLock.Lock() 117 mimeTypes[extension] = mimeType 118 mimeTypesLower[extLower] = mimeType 119 mimeLock.Unlock() 120 return nil 121 }