...
Run Format

Source file src/mime/type.go

     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	}
   122	

View as plain text