index.js (3663B)
1 /*! 2 * mime-types 3 * Copyright(c) 2014 Jonathan Ong 4 * Copyright(c) 2015 Douglas Christopher Wilson 5 * MIT Licensed 6 */ 7 8 'use strict' 9 10 /** 11 * Module dependencies. 12 * @private 13 */ 14 15 var db = require('mime-db') 16 var extname = require('path').extname 17 18 /** 19 * Module variables. 20 * @private 21 */ 22 23 var EXTRACT_TYPE_REGEXP = /^\s*([^;\s]*)(?:;|\s|$)/ 24 var TEXT_TYPE_REGEXP = /^text\//i 25 26 /** 27 * Module exports. 28 * @public 29 */ 30 31 exports.charset = charset 32 exports.charsets = { lookup: charset } 33 exports.contentType = contentType 34 exports.extension = extension 35 exports.extensions = Object.create(null) 36 exports.lookup = lookup 37 exports.types = Object.create(null) 38 39 // Populate the extensions/types maps 40 populateMaps(exports.extensions, exports.types) 41 42 /** 43 * Get the default charset for a MIME type. 44 * 45 * @param {string} type 46 * @return {boolean|string} 47 */ 48 49 function charset (type) { 50 if (!type || typeof type !== 'string') { 51 return false 52 } 53 54 // TODO: use media-typer 55 var match = EXTRACT_TYPE_REGEXP.exec(type) 56 var mime = match && db[match[1].toLowerCase()] 57 58 if (mime && mime.charset) { 59 return mime.charset 60 } 61 62 // default text/* to utf-8 63 if (match && TEXT_TYPE_REGEXP.test(match[1])) { 64 return 'UTF-8' 65 } 66 67 return false 68 } 69 70 /** 71 * Create a full Content-Type header given a MIME type or extension. 72 * 73 * @param {string} str 74 * @return {boolean|string} 75 */ 76 77 function contentType (str) { 78 // TODO: should this even be in this module? 79 if (!str || typeof str !== 'string') { 80 return false 81 } 82 83 var mime = str.indexOf('/') === -1 84 ? exports.lookup(str) 85 : str 86 87 if (!mime) { 88 return false 89 } 90 91 // TODO: use content-type or other module 92 if (mime.indexOf('charset') === -1) { 93 var charset = exports.charset(mime) 94 if (charset) mime += '; charset=' + charset.toLowerCase() 95 } 96 97 return mime 98 } 99 100 /** 101 * Get the default extension for a MIME type. 102 * 103 * @param {string} type 104 * @return {boolean|string} 105 */ 106 107 function extension (type) { 108 if (!type || typeof type !== 'string') { 109 return false 110 } 111 112 // TODO: use media-typer 113 var match = EXTRACT_TYPE_REGEXP.exec(type) 114 115 // get extensions 116 var exts = match && exports.extensions[match[1].toLowerCase()] 117 118 if (!exts || !exts.length) { 119 return false 120 } 121 122 return exts[0] 123 } 124 125 /** 126 * Lookup the MIME type for a file path/extension. 127 * 128 * @param {string} path 129 * @return {boolean|string} 130 */ 131 132 function lookup (path) { 133 if (!path || typeof path !== 'string') { 134 return false 135 } 136 137 // get the extension ("ext" or ".ext" or full path) 138 var extension = extname('x.' + path) 139 .toLowerCase() 140 .substr(1) 141 142 if (!extension) { 143 return false 144 } 145 146 return exports.types[extension] || false 147 } 148 149 /** 150 * Populate the extensions and types maps. 151 * @private 152 */ 153 154 function populateMaps (extensions, types) { 155 // source preference (least -> most) 156 var preference = ['nginx', 'apache', undefined, 'iana'] 157 158 Object.keys(db).forEach(function forEachMimeType (type) { 159 var mime = db[type] 160 var exts = mime.extensions 161 162 if (!exts || !exts.length) { 163 return 164 } 165 166 // mime -> extensions 167 extensions[type] = exts 168 169 // extension -> mime 170 for (var i = 0; i < exts.length; i++) { 171 var extension = exts[i] 172 173 if (types[extension]) { 174 var from = preference.indexOf(db[types[extension]].source) 175 var to = preference.indexOf(mime.source) 176 177 if (types[extension] !== 'application/octet-stream' && 178 (from > to || (from === to && types[extension].substr(0, 12) === 'application/'))) { 179 // skip the remapping 180 continue 181 } 182 } 183 184 // set the extension -> mime 185 types[extension] = type 186 } 187 }) 188 }