You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
105 lines
2.6 KiB
105 lines
2.6 KiB
'use strict'
|
|
const path = require('path')
|
|
const Koa = require('koa')
|
|
const serve = require('koa-static')
|
|
const convert = require('koa-convert')
|
|
const serveIndex = require('koa-serve-index')
|
|
const morgan = require('koa-morgan')
|
|
const compress = require('koa-compress')
|
|
const streamLogStats = require('stream-log-stats')
|
|
const cors = require('kcors')
|
|
const conditional = require('koa-conditional-get');
|
|
const etag = require('koa-etag');
|
|
|
|
/**
|
|
* @module local-web-server
|
|
*/
|
|
module.exports = getApp
|
|
|
|
function getApp (options) {
|
|
options = Object.assign({
|
|
static: {},
|
|
serveIndex: {},
|
|
log: {},
|
|
compress: false,
|
|
blacklist: []
|
|
}, options)
|
|
|
|
const log = options.log
|
|
log.options = log.options || {}
|
|
|
|
const app = new Koa()
|
|
|
|
/* CORS: allow from any origin */
|
|
app.use(convert(cors()))
|
|
|
|
/* path blacklist */
|
|
if (options.blacklist.length) {
|
|
app.use(function pathBlacklist (ctx, next) {
|
|
if (options.blacklist.some(regexp => regexp.test(ctx.path))) {
|
|
ctx.throw(403, 'Blacklisted')
|
|
} else {
|
|
return next()
|
|
}
|
|
})
|
|
}
|
|
|
|
app.use(convert(conditional()))
|
|
app.use(convert(etag()))
|
|
|
|
/* mime-type overrides */
|
|
if (options.mime) {
|
|
app.use((ctx, next) => {
|
|
return next().then(() => {
|
|
const reqPathExtension = path.extname(ctx.path).slice(1)
|
|
Object.keys(options.mime).forEach(mimeType => {
|
|
const extsToOverride = options.mime[mimeType]
|
|
if (extsToOverride.indexOf(reqPathExtension) > -1) ctx.type = mimeType
|
|
})
|
|
})
|
|
})
|
|
}
|
|
|
|
/* compress response */
|
|
if (options.compress) {
|
|
app.use(convert(compress()))
|
|
}
|
|
|
|
/* special case log formats */
|
|
if (log.format) {
|
|
if (log.format === 'none'){
|
|
log.format = undefined
|
|
} else if (log.format === 'logstalgia') {
|
|
morgan.token('date', logstalgiaDate)
|
|
log.format = 'combined'
|
|
}
|
|
/* if no specific log format was requested, show log stats */
|
|
} else {
|
|
log.format = 'common'
|
|
log.options.stream = streamLogStats({ refreshRate: 500 })
|
|
}
|
|
if (log.format) app.use(convert(morgan.middleware(log.format, log.options)))
|
|
|
|
/* serve static files */
|
|
if (options.static.root) {
|
|
app.use(convert(serve(options.static.root, options.static.options)))
|
|
}
|
|
|
|
/* serve directory index */
|
|
if (options.serveIndex.path) {
|
|
app.use(convert(serveIndex(options.serveIndex.path, options.serveIndex.options)))
|
|
}
|
|
|
|
return app
|
|
}
|
|
|
|
function logstalgiaDate () {
|
|
var d = new Date()
|
|
return (`${d.getDate()}/${d.getUTCMonth()}/${d.getFullYear()}:${d.toTimeString()}`)
|
|
.replace('GMT', '')
|
|
.replace(' (BST)', '')
|
|
}
|
|
|
|
process.on('unhandledRejection', (reason, p) => {
|
|
throw reason
|
|
})
|