Backend half

This commit is contained in:
2025-07-11 19:56:28 +02:00
parent fa868e7c1d
commit 8600fa7c1d
19426 changed files with 3750448 additions and 8108 deletions
+159 -14
View File
@@ -14,12 +14,14 @@
var createError = require('http-errors')
var debug = require('debug')('send')
var deprecate = require('depd')('send')
var destroy = require('destroy')
var encodeUrl = require('encodeurl')
var escapeHtml = require('escape-html')
var etag = require('etag')
var fresh = require('fresh')
var fs = require('fs')
var mime = require('mime-types')
var mime = require('mime')
var ms = require('ms')
var onFinished = require('on-finished')
var parseRange = require('range-parser')
@@ -66,6 +68,7 @@ var UP_PATH_REGEXP = /(?:^|[\\/])\.\.(?:[\\/]|$)/
*/
module.exports = send
module.exports.mime = mime
/**
* Return a `SendStream` for `req` and `path`.
@@ -119,6 +122,17 @@ function SendStream (req, path, options) {
throw new TypeError('dotfiles option must be "allow", "deny", or "ignore"')
}
this._hidden = Boolean(opts.hidden)
if (opts.hidden !== undefined) {
deprecate('hidden: use dotfiles: \'' + (this._hidden ? 'allow' : 'ignore') + '\' instead')
}
// legacy support
if (opts.dotfiles === undefined) {
this._dotfiles = undefined
}
this._extensions = opts.extensions !== undefined
? normalizeList(opts.extensions, 'extensions option')
: []
@@ -146,6 +160,10 @@ function SendStream (req, path, options) {
this._root = opts.root
? resolve(opts.root)
: null
if (!this._root && opts.from) {
this.from(opts.from)
}
}
/**
@@ -154,6 +172,90 @@ function SendStream (req, path, options) {
util.inherits(SendStream, Stream)
/**
* Enable or disable etag generation.
*
* @param {Boolean} val
* @return {SendStream}
* @api public
*/
SendStream.prototype.etag = deprecate.function(function etag (val) {
this._etag = Boolean(val)
debug('etag %s', this._etag)
return this
}, 'send.etag: pass etag as option')
/**
* Enable or disable "hidden" (dot) files.
*
* @param {Boolean} path
* @return {SendStream}
* @api public
*/
SendStream.prototype.hidden = deprecate.function(function hidden (val) {
this._hidden = Boolean(val)
this._dotfiles = undefined
debug('hidden %s', this._hidden)
return this
}, 'send.hidden: use dotfiles option')
/**
* Set index `paths`, set to a falsy
* value to disable index support.
*
* @param {String|Boolean|Array} paths
* @return {SendStream}
* @api public
*/
SendStream.prototype.index = deprecate.function(function index (paths) {
var index = !paths ? [] : normalizeList(paths, 'paths argument')
debug('index %o', paths)
this._index = index
return this
}, 'send.index: pass index as option')
/**
* Set root `path`.
*
* @param {String} path
* @return {SendStream}
* @api public
*/
SendStream.prototype.root = function root (path) {
this._root = resolve(String(path))
debug('root %s', this._root)
return this
}
SendStream.prototype.from = deprecate.function(SendStream.prototype.root,
'send.from: pass root as option')
SendStream.prototype.root = deprecate.function(SendStream.prototype.root,
'send.root: pass root as option')
/**
* Set max-age to `maxAge`.
*
* @param {Number} maxAge
* @return {SendStream}
* @api public
*/
SendStream.prototype.maxage = deprecate.function(function maxage (maxAge) {
this._maxage = typeof maxAge === 'string'
? ms(maxAge)
: Number(maxAge)
this._maxage = !isNaN(this._maxage)
? Math.min(Math.max(0, this._maxage), MAX_MAXAGE)
: 0
debug('max-age %d', this._maxage)
return this
}, 'send.maxage: pass maxAge as option')
/**
* Emit error with `status`.
*
@@ -456,8 +558,17 @@ SendStream.prototype.pipe = function pipe (res) {
// dotfile handling
if (containsDotFile(parts)) {
debug('%s dotfile "%s"', this._dotfiles, path)
switch (this._dotfiles) {
var access = this._dotfiles
// legacy support
if (access === undefined) {
access = parts[parts.length - 1][0] === '.'
? (this._hidden ? 'allow' : 'ignore')
: 'allow'
}
debug('%s dotfile "%s"', access, path)
switch (access) {
case 'allow':
break
case 'deny':
@@ -496,7 +607,7 @@ SendStream.prototype.send = function send (path, stat) {
var ranges = req.headers.range
var offset = options.start || 0
if (res.headersSent) {
if (headersSent(res)) {
// impossible to send now
this.headersAlreadySent()
return
@@ -603,14 +714,12 @@ SendStream.prototype.sendFile = function sendFile (path) {
debug('stat "%s"', path)
fs.stat(path, function onstat (err, stat) {
var pathEndsWithSep = path[path.length - 1] === sep
if (err && err.code === 'ENOENT' && !extname(path) && !pathEndsWithSep) {
if (err && err.code === 'ENOENT' && !extname(path) && path[path.length - 1] !== sep) {
// not found, check extensions
return next(err)
}
if (err) return self.onStatError(err)
if (stat.isDirectory()) return self.redirect(path)
if (pathEndsWithSep) return self.error(404)
self.emit('file', path, stat)
self.send(path, stat)
})
@@ -683,7 +792,7 @@ SendStream.prototype.stream = function stream (path, options) {
// cleanup
function cleanup () {
stream.destroy()
destroy(stream, true)
}
// response finished, cleanup
@@ -717,11 +826,17 @@ SendStream.prototype.type = function type (path) {
if (res.getHeader('Content-Type')) return
var ext = extname(path)
var type = mime.contentType(ext) || 'application/octet-stream'
var type = mime.lookup(path)
if (!type) {
debug('no content-type')
return
}
var charset = mime.charsets.lookup(type)
debug('content-type %s', type)
res.setHeader('Content-Type', type)
res.setHeader('Content-Type', type + (charset ? '; charset=' + charset : ''))
}
/**
@@ -775,8 +890,10 @@ SendStream.prototype.setHeader = function setHeader (path, stat) {
*/
function clearHeaders (res) {
for (const header of res.getHeaderNames()) {
res.removeHeader(header)
var headers = getHeaderNames(res)
for (var i = 0; i < headers.length; i++) {
res.removeHeader(headers[i])
}
}
@@ -884,10 +1001,24 @@ function decode (path) {
}
}
/**
* Get the header names on a respnse.
*
* @param {object} res
* @returns {array[string]}
* @private
*/
function getHeaderNames (res) {
return typeof res.getHeaderNames !== 'function'
? Object.keys(res._headers || {})
: res.getHeaderNames()
}
/**
* Determine if emitter has listeners of a given type.
*
* The way to do this check is done three different ways in Node.js >= 0.10
* The way to do this check is done three different ways in Node.js >= 0.8
* so this consolidates them into a minimal set using instance methods.
*
* @param {EventEmitter} emitter
@@ -904,6 +1035,20 @@ function hasListeners (emitter, type) {
return count > 0
}
/**
* Determine if the response headers have been sent.
*
* @param {object} res
* @returns {boolean}
* @private
*/
function headersSent (res) {
return typeof res.headersSent !== 'boolean'
? Boolean(res._header)
: res.headersSent
}
/**
* Normalize the index option into an array.
*