212 lines
4.4 KiB
Plaintext
212 lines
4.4 KiB
Plaintext
/*!
|
|
* mime-types
|
|
* Copyright(c) 2014 Jonathan Ong
|
|
* Copyright(c) 2015 Douglas Christopher Wilson
|
|
* MIT Licensed
|
|
*/
|
|
|
|
'use strict'
|
|
|
|
/**
|
|
* Module dependencies.
|
|
* @private
|
|
*/
|
|
|
|
var db = require('mime-db')
|
|
var extname = require('path').extname
|
|
var mimeScore = require('./mimeScore')
|
|
|
|
/**
|
|
* Module variables.
|
|
* @private
|
|
*/
|
|
|
|
var EXTRACT_TYPE_REGEXP = /^\s*([^;\s]*)(?:;|\s|$)/
|
|
var TEXT_TYPE_REGEXP = /^text\//i
|
|
|
|
/**
|
|
* Module exports.
|
|
* @public
|
|
*/
|
|
|
|
exports.charset = charset
|
|
exports.charsets = { lookup: charset }
|
|
exports.contentType = contentType
|
|
exports.extension = extension
|
|
exports.extensions = Object.create(null)
|
|
exports.lookup = lookup
|
|
exports.types = Object.create(null)
|
|
exports._extensionConflicts = []
|
|
|
|
// Populate the extensions/types maps
|
|
populateMaps(exports.extensions, exports.types)
|
|
|
|
/**
|
|
* Get the default charset for a MIME type.
|
|
*
|
|
* @param {string} type
|
|
* @return {boolean|string}
|
|
*/
|
|
|
|
function charset (type) {
|
|
if (!type || typeof type !== 'string') {
|
|
return false
|
|
}
|
|
|
|
// TODO: use media-typer
|
|
var match = EXTRACT_TYPE_REGEXP.exec(type)
|
|
var mime = match && db[match[1].toLowerCase()]
|
|
|
|
if (mime && mime.charset) {
|
|
return mime.charset
|
|
}
|
|
|
|
// default text/* to utf-8
|
|
if (match && TEXT_TYPE_REGEXP.test(match[1])) {
|
|
return 'UTF-8'
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
/**
|
|
* Create a full Content-Type header given a MIME type or extension.
|
|
*
|
|
* @param {string} str
|
|
* @return {boolean|string}
|
|
*/
|
|
|
|
function contentType (str) {
|
|
// TODO: should this even be in this module?
|
|
if (!str || typeof str !== 'string') {
|
|
return false
|
|
}
|
|
|
|
var mime = str.indexOf('/') === -1 ? exports.lookup(str) : str
|
|
|
|
if (!mime) {
|
|
return false
|
|
}
|
|
|
|
// TODO: use content-type or other module
|
|
if (mime.indexOf('charset') === -1) {
|
|
var charset = exports.charset(mime)
|
|
if (charset) mime += '; charset=' + charset.toLowerCase()
|
|
}
|
|
|
|
return mime
|
|
}
|
|
|
|
/**
|
|
* Get the default extension for a MIME type.
|
|
*
|
|
* @param {string} type
|
|
* @return {boolean|string}
|
|
*/
|
|
|
|
function extension (type) {
|
|
if (!type || typeof type !== 'string') {
|
|
return false
|
|
}
|
|
|
|
// TODO: use media-typer
|
|
var match = EXTRACT_TYPE_REGEXP.exec(type)
|
|
|
|
// get extensions
|
|
var exts = match && exports.extensions[match[1].toLowerCase()]
|
|
|
|
if (!exts || !exts.length) {
|
|
return false
|
|
}
|
|
|
|
return exts[0]
|
|
}
|
|
|
|
/**
|
|
* Lookup the MIME type for a file path/extension.
|
|
*
|
|
* @param {string} path
|
|
* @return {boolean|string}
|
|
*/
|
|
|
|
function lookup (path) {
|
|
if (!path || typeof path !== 'string') {
|
|
return false
|
|
}
|
|
|
|
// get the extension ("ext" or ".ext" or full path)
|
|
var extension = extname('x.' + path)
|
|
.toLowerCase()
|
|
.slice(1)
|
|
|
|
if (!extension) {
|
|
return false
|
|
}
|
|
|
|
return exports.types[extension] || false
|
|
}
|
|
|
|
/**
|
|
* Populate the extensions and types maps.
|
|
* @private
|
|
*/
|
|
|
|
function populateMaps (extensions, types) {
|
|
Object.keys(db).forEach(function forEachMimeType (type) {
|
|
var mime = db[type]
|
|
var exts = mime.extensions
|
|
|
|
if (!exts || !exts.length) {
|
|
return
|
|
}
|
|
|
|
// mime -> extensions
|
|
extensions[type] = exts
|
|
|
|
// extension -> mime
|
|
for (var i = 0; i < exts.length; i++) {
|
|
var extension = exts[i]
|
|
types[extension] = _preferredType(extension, types[extension], type)
|
|
|
|
// DELETE (eventually): Capture extension->type maps that change as a
|
|
// result of switching to mime-score. This is just to help make reviewing
|
|
// PR #119 easier, and can be removed once that PR is approved.
|
|
const legacyType = _preferredTypeLegacy(
|
|
extension,
|
|
types[extension],
|
|
type
|
|
)
|
|
if (legacyType !== types[extension]) {
|
|
exports._extensionConflicts.push([extension, legacyType, types[extension]])
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
// Resolve type conflict using mime-score
|
|
function _preferredType (ext, type0, type1) {
|
|
var score0 = type0 ? mimeScore(type0, db[type0].source) : 0
|
|
var score1 = type1 ? mimeScore(type1, db[type1].source) : 0
|
|
|
|
return score0 > score1 ? type0 : type1
|
|
}
|
|
|
|
// Resolve type conflict using pre-mime-score logic
|
|
function _preferredTypeLegacy (ext, type0, type1) {
|
|
var SOURCE_RANK = ['nginx', 'apache', undefined, 'iana']
|
|
|
|
var score0 = type0 ? SOURCE_RANK.indexOf(db[type0].source) : 0
|
|
var score1 = type1 ? SOURCE_RANK.indexOf(db[type1].source) : 0
|
|
|
|
if (
|
|
exports.types[extension] !== 'application/octet-stream' &&
|
|
(score0 > score1 ||
|
|
(score0 === score1 &&
|
|
exports.types[extension]?.slice(0, 12) === 'application/'))
|
|
) {
|
|
return type0
|
|
}
|
|
|
|
return score0 > score1 ? type0 : type1
|
|
}
|