2022-07-11 23:29:21 +00:00
|
|
|
|
|
|
|
const contentDisposition = require('content-disposition')
|
2022-07-12 01:51:22 +00:00
|
|
|
const SimpleDataStore = require('./../utils/SimpleDataStore')
|
|
|
|
const paths = require('./../pathsController')
|
|
|
|
const utils = require('./../utilsController')
|
|
|
|
const logger = require('./../../logger')
|
2022-07-11 23:29:21 +00:00
|
|
|
|
|
|
|
class ServeStatic {
|
|
|
|
directory
|
|
|
|
contentDispositionStore
|
|
|
|
contentTypesMaps
|
|
|
|
|
|
|
|
async #setContentDisposition () {}
|
|
|
|
#setContentType () {}
|
|
|
|
|
|
|
|
constructor (directory, options = {}) {
|
|
|
|
logger.error('new ServeStatic()')
|
|
|
|
if (!directory || typeof directory !== 'string') {
|
|
|
|
throw new TypeError('Root directory must be set')
|
|
|
|
}
|
|
|
|
|
|
|
|
this.directory = directory
|
|
|
|
|
|
|
|
// Init Content-Type overrides
|
|
|
|
if (typeof options.overrideContentTypes === 'object') {
|
|
|
|
this.contentTypesMaps = new Map()
|
|
|
|
|
|
|
|
const types = Object.keys(options.overrideContentTypes)
|
|
|
|
for (const type of types) {
|
|
|
|
const extensions = options.overrideContentTypes[type]
|
|
|
|
if (Array.isArray(extensions)) {
|
|
|
|
for (const extension of extensions) {
|
|
|
|
this.contentTypesMaps.set(extension, type)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this.contentTypesMaps.size) {
|
|
|
|
this.#setContentType = (res, path, stat) => {
|
|
|
|
// Do only if accessing files from uploads' root directory (i.e. not thumbs, etc.)
|
|
|
|
const relpath = path.replace(paths.uploads, '')
|
|
|
|
if (relpath.indexOf('/', 1) === -1) {
|
|
|
|
const name = relpath.substring(1)
|
|
|
|
const extname = utils.extname(name).substring(1)
|
|
|
|
const contentType = this.contentTypesMaps.get(extname)
|
|
|
|
if (contentType) {
|
|
|
|
res.set('Content-Type', contentType)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
this.contentTypesMaps = undefined
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Init Content-Disposition store and setHeaders function if required
|
|
|
|
if (options.setContentDisposition) {
|
|
|
|
this.contentDispositionStore = new SimpleDataStore(
|
|
|
|
options.contentDispositionOptions || {
|
|
|
|
limit: 50,
|
|
|
|
strategy: SimpleDataStore.STRATEGIES[0]
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
this.#setContentDisposition = async (res, path, stat) => {
|
|
|
|
// Do only if accessing files from uploads' root directory (i.e. not thumbs, etc.)
|
|
|
|
const relpath = path.replace(paths.uploads, '')
|
|
|
|
if (relpath.indexOf('/', 1) !== -1) return
|
|
|
|
const name = relpath.substring(1)
|
|
|
|
try {
|
|
|
|
let original = this.contentDispositionStore.get(name)
|
|
|
|
if (original === undefined) {
|
|
|
|
this.contentDispositionStore.hold(name)
|
|
|
|
original = await utils.db.table('files')
|
|
|
|
.where('name', name)
|
|
|
|
.select('original')
|
|
|
|
.first()
|
|
|
|
.then(_file => {
|
|
|
|
this.contentDispositionStore.set(name, _file.original)
|
|
|
|
return _file.original
|
|
|
|
})
|
|
|
|
}
|
|
|
|
if (original) {
|
|
|
|
res.set('Content-Disposition', contentDisposition(original, { type: 'inline' }))
|
|
|
|
}
|
|
|
|
} catch (error) {
|
|
|
|
this.contentDispositionStore.delete(name)
|
|
|
|
logger.error(error)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
logger.debug('Inititated SimpleDataStore for Content-Disposition: ' +
|
|
|
|
`{ limit: ${this.contentDispositionStore.limit}, strategy: "${this.contentDispositionStore.strategy}" }`)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
async #setHeaders (req, res) {
|
|
|
|
logger.log('ServeStatic.setHeaders()')
|
|
|
|
|
|
|
|
this.#setContentType(req, res)
|
|
|
|
|
|
|
|
// Only set Content-Disposition on GET requests
|
|
|
|
if (req.method === 'GET') {
|
|
|
|
await this.#setContentDisposition(req, res)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
async #middleware (req, res, next) {
|
|
|
|
logger.log(`ServeStatic.middleware(): ${this.directory}, ${req.path}`)
|
|
|
|
|
|
|
|
// TODO
|
|
|
|
}
|
|
|
|
|
|
|
|
get middleware () {
|
|
|
|
return this.#middleware.bind(this)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
module.exports = ServeStatic
|