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

9 years ago
9 years ago
9 years ago
9 years ago
  1. 'use strict'
  2. const path = require('path')
  3. const Koa = require('koa')
  4. const serve = require('koa-static')
  5. const convert = require('koa-convert')
  6. const serveIndex = require('koa-serve-index')
  7. const morgan = require('koa-morgan')
  8. const compress = require('koa-compress')
  9. const streamLogStats = require('stream-log-stats')
  10. const cors = require('kcors')
  11. const conditional = require('koa-conditional-get');
  12. const etag = require('koa-etag');
  13. /**
  14. * @module local-web-server
  15. */
  16. module.exports = getApp
  17. function getApp (options) {
  18. options = Object.assign({
  19. static: {},
  20. serveIndex: {},
  21. log: {},
  22. compress: false,
  23. blacklist: []
  24. }, options)
  25. const log = options.log
  26. log.options = log.options || {}
  27. const app = new Koa()
  28. /* CORS: allow from any origin */
  29. app.use(convert(cors()))
  30. /* path blacklist */
  31. if (options.blacklist.length) {
  32. app.use(function pathBlacklist (ctx, next) {
  33. if (options.blacklist.some(regexp => regexp.test(ctx.path))) {
  34. ctx.throw(403, 'Blacklisted')
  35. } else {
  36. return next()
  37. }
  38. })
  39. }
  40. app.use(convert(conditional()))
  41. app.use(convert(etag()))
  42. /* mime-type overrides */
  43. if (options.mime) {
  44. app.use((ctx, next) => {
  45. return next().then(() => {
  46. const reqPathExtension = path.extname(ctx.path).slice(1)
  47. Object.keys(options.mime).forEach(mimeType => {
  48. const extsToOverride = options.mime[mimeType]
  49. if (extsToOverride.indexOf(reqPathExtension) > -1) ctx.type = mimeType
  50. })
  51. })
  52. })
  53. }
  54. /* compress response */
  55. if (options.compress) {
  56. app.use(convert(compress()))
  57. }
  58. /* special case log formats */
  59. if (log.format) {
  60. if (log.format === 'none'){
  61. log.format = undefined
  62. } else if (log.format === 'logstalgia') {
  63. morgan.token('date', logstalgiaDate)
  64. log.format = 'combined'
  65. }
  66. /* if no specific log format was requested, show log stats */
  67. } else {
  68. log.format = 'common'
  69. log.options.stream = streamLogStats({ refreshRate: 500 })
  70. }
  71. if (log.format) app.use(convert(morgan.middleware(log.format, log.options)))
  72. /* serve static files */
  73. if (options.static.root) {
  74. app.use(convert(serve(options.static.root, options.static.options)))
  75. }
  76. /* serve directory index */
  77. if (options.serveIndex.path) {
  78. app.use(convert(serveIndex(options.serveIndex.path, options.serveIndex.options)))
  79. }
  80. return app
  81. }
  82. function logstalgiaDate () {
  83. var d = new Date()
  84. return (`${d.getDate()}/${d.getUTCMonth()}/${d.getFullYear()}:${d.toTimeString()}`)
  85. .replace('GMT', '')
  86. .replace(' (BST)', '')
  87. }
  88. process.on('unhandledRejection', (reason, p) => {
  89. throw reason
  90. })