mirror of
https://github.com/BobbyWibowo/lolisafe.git
synced 2024-12-15 00:46:22 +00:00
414afc7ae6
when used on non-root paths
146 lines
3.7 KiB
JavaScript
146 lines
3.7 KiB
JavaScript
/*
|
|
* ServeLiveDirectory is a middleware wrapper for LiveDirectory library.
|
|
*
|
|
* It is mainly intended to add Conditional GETs support,
|
|
* which involves handling cache-related headers such as
|
|
* If-Match, If-Unmodified-Since, ETag, etc.
|
|
*
|
|
* LiveDirectory monitors and caches all the files in the configure directory into memory,
|
|
* which allows very fast lookups, thus allowing multiple instances of this middleware
|
|
* to be used together, if needed.
|
|
*
|
|
* However, due to the fact that it caches all the files into memory,
|
|
* this may not be the best choice in an environment where memory space is a premium.
|
|
*/
|
|
|
|
const LiveDirectory = require('live-directory')
|
|
const serveUtils = require('./../utils/serveUtils')
|
|
|
|
class ServeLiveDirectory {
|
|
instance
|
|
|
|
#options
|
|
|
|
constructor (directory, options = {}) {
|
|
if (!directory || typeof directory !== 'string') {
|
|
throw new TypeError('Root directory must be set')
|
|
}
|
|
|
|
this.directory = serveUtils.forwardSlashes(directory)
|
|
|
|
// Ensure does not end with a forward slash
|
|
if (this.directory.endsWith('/')) {
|
|
this.directory = this.directory.slice(0, -1)
|
|
}
|
|
|
|
if (options.etag === undefined) {
|
|
options.etag = true
|
|
}
|
|
|
|
if (options.lastModified === undefined) {
|
|
options.lastModified = true
|
|
}
|
|
|
|
if (options.setHeaders && typeof options.setHeaders !== 'function') {
|
|
throw new TypeError('Middleware option setHeaders must be a function')
|
|
}
|
|
|
|
const instanceOptions = Object.assign({}, options.instanceOptions)
|
|
instanceOptions.path = this.directory
|
|
|
|
delete options.instanceOptions
|
|
|
|
if (!instanceOptions.ignore) {
|
|
instanceOptions.ignore = path => {
|
|
// ignore dot files
|
|
return path.startsWith('.')
|
|
}
|
|
}
|
|
|
|
this.instance = new LiveDirectory(instanceOptions)
|
|
|
|
this.#options = options
|
|
}
|
|
|
|
get (path) {
|
|
const file = this.instance.get(path)
|
|
|
|
return file
|
|
}
|
|
|
|
handler (req, res, path, file) {
|
|
// Set Content-Type
|
|
res.type(file.extension)
|
|
|
|
// Set header fields
|
|
this.#setHeaders(req, res, file)
|
|
|
|
// Conditional GET support
|
|
if (serveUtils.assertConditionalGET(req, res)) {
|
|
return res.end()
|
|
}
|
|
|
|
// HEAD support
|
|
if (req.method === 'HEAD') {
|
|
return res.end()
|
|
}
|
|
|
|
return res.send(file.buffer)
|
|
}
|
|
|
|
ready () {
|
|
// Returns a promise which resolves to true once LiveDirectory instance is ready
|
|
return this.instance.ready()
|
|
}
|
|
|
|
#middleware (req, res, next) {
|
|
// Only process GET and HEAD requests
|
|
if (req.method !== 'GET' && req.method !== 'HEAD') {
|
|
return next()
|
|
}
|
|
|
|
// If root path is set, ensure it matches the request
|
|
let path = req.path
|
|
if (this.#options.root) {
|
|
if (path.indexOf(this.#options.root) === 0) {
|
|
// Re-map path for internal .get()
|
|
path = path.replace(this.#options.root, '')
|
|
} else {
|
|
// Immediately proceed to next middleware otherwise
|
|
return next()
|
|
}
|
|
}
|
|
|
|
const file = this.get(path)
|
|
if (file === undefined) {
|
|
return next()
|
|
}
|
|
|
|
return this.handler(req, res, path, file)
|
|
}
|
|
|
|
#setHeaders (req, res, file) {
|
|
// Always do external setHeaders function first,
|
|
// in case it will overwrite the following default headers anyways
|
|
if (this.#options.setHeaders) {
|
|
this.#options.setHeaders(req, res)
|
|
}
|
|
|
|
if (this.#options.lastModified && !res.get('Last-Modified')) {
|
|
const modified = new Date(file.last_update).toUTCString()
|
|
res.header('Last-Modified', modified)
|
|
}
|
|
|
|
if (this.#options.etag && !res.get('ETag')) {
|
|
const val = file.etag
|
|
res.header('ETag', val)
|
|
}
|
|
}
|
|
|
|
get middleware () {
|
|
return this.#middleware.bind(this)
|
|
}
|
|
}
|
|
|
|
module.exports = ServeLiveDirectory
|