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.

214 lines
5.2 KiB

9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
  1. 'use strict'
  2. const arrayify = require('array-back')
  3. const path = require('path')
  4. const url = require('url')
  5. const debug = require('debug')('local-web-server')
  6. const mw = require('./middleware')
  7. class MiddlewareStack extends Array {
  8. constructor (options) {
  9. super()
  10. this.options = options
  11. options = Object.assign({
  12. cacheControl: {},
  13. spa: null,
  14. compress: false,
  15. mime: {},
  16. forbid: [],
  17. rewrite: [],
  18. verbose: false,
  19. mocks: []
  20. }, options)
  21. if (options.verbose) {
  22. process.env.DEBUG = '*'
  23. }
  24. options.rewrite = arrayify(options.rewrite)
  25. options.forbid = arrayify(options.forbid)
  26. options.mocks = arrayify(options.mocks)
  27. }
  28. add (middleware) {
  29. this.push(middleware)
  30. return this
  31. }
  32. /**
  33. * allow from any origin
  34. */
  35. addCors () {
  36. this.push(require('kcors')())
  37. return this
  38. }
  39. /* pretty print JSON */
  40. addJson () {
  41. this.push(require('koa-json')())
  42. return this
  43. }
  44. /* rewrite rules */
  45. addRewrite () {
  46. const options = this.options.rewrite
  47. if (options.length) {
  48. options.forEach(route => {
  49. if (route.to) {
  50. /* `to` address is remote if the url specifies a host */
  51. if (url.parse(route.to).host) {
  52. const _ = require('koa-route')
  53. debug('proxy rewrite', `${route.from} -> ${route.to}`)
  54. this.push(_.all(route.from, mw.proxyRequest(route)))
  55. } else {
  56. const rewrite = require('koa-rewrite')
  57. const rmw = rewrite(route.from, route.to)
  58. rmw._name = 'rewrite'
  59. this.push(rmw)
  60. }
  61. }
  62. })
  63. }
  64. return this
  65. }
  66. /* must come after rewrite.
  67. See https://github.com/nodejitsu/node-http-proxy/issues/180. */
  68. addBodyParser () {
  69. this.push(require('koa-bodyparser')())
  70. return this
  71. }
  72. /* path blacklist */
  73. addBlacklist () {
  74. const options = this.options.forbid
  75. if (options.length) {
  76. debug('forbid', options.join(', '))
  77. this.push(mw.blacklist(options))
  78. }
  79. return this
  80. }
  81. /* cache */
  82. addCache () {
  83. if (!this.options['no-cache']) {
  84. this.push(require('koa-conditional-get')())
  85. this.push(require('koa-etag')())
  86. }
  87. return this
  88. }
  89. /* mime-type overrides */
  90. addMimeType () {
  91. const options = this.options.mime
  92. if (options) {
  93. debug('mime override', JSON.stringify(options))
  94. this.push(mw.mime(options))
  95. }
  96. return this
  97. }
  98. /* compress response */
  99. addCompression () {
  100. if (this.options.compress) {
  101. const compress = require('koa-compress')
  102. debug('compression', 'enabled')
  103. this.push(compress())
  104. }
  105. return this
  106. }
  107. /* Logging */
  108. addLogging (format, options) {
  109. format = this.options.server['log-format'] || format
  110. options = options || {}
  111. if (this.options.verbose && !format) {
  112. format = 'none'
  113. }
  114. if (format !== 'none') {
  115. const morgan = require('koa-morgan')
  116. if (!format) {
  117. const streamLogStats = require('stream-log-stats')
  118. options.stream = streamLogStats({ refreshRate: 500 })
  119. this.push(morgan('common', options))
  120. } else if (format === 'logstalgia') {
  121. morgan.token('date', () => {
  122. var d = new Date()
  123. return (`${d.getDate()}/${d.getUTCMonth()}/${d.getFullYear()}:${d.toTimeString()}`).replace('GMT', '').replace(' (BST)', '')
  124. })
  125. this.push(morgan('combined', options))
  126. } else {
  127. this.push(morgan(format, options))
  128. }
  129. }
  130. return this
  131. }
  132. /* Mock Responses */
  133. addMockResponses () {
  134. const options = this.options.mocks
  135. options.forEach(mock => {
  136. if (mock.module) {
  137. mock.responses = require(path.resolve(path.join(this.options.static.root, mock.module)))
  138. }
  139. if (mock.responses) {
  140. this.push(mw.mockResponses(mock.route, mock.responses))
  141. } else if (mock.response) {
  142. mock.target = {
  143. request: mock.request,
  144. response: mock.response
  145. }
  146. this.push(mw.mockResponses(mock.route, mock.target))
  147. }
  148. })
  149. return this
  150. }
  151. /* for any URL not matched by static (e.g. `/search`), serve the SPA */
  152. addSpa () {
  153. if (this.options.spa) {
  154. const historyApiFallback = require('koa-connect-history-api-fallback')
  155. debug('SPA', this.options.spa)
  156. this.push(historyApiFallback({
  157. index: this.options.spa,
  158. verbose: this.options.verbose
  159. }))
  160. }
  161. return this
  162. }
  163. /* serve static files */
  164. addStatic (root, options) {
  165. root = this.options.server.directory || root || process.cwd()
  166. options = Object.assign({ hidden: true }, options)
  167. if (root) {
  168. const serve = require('koa-static')
  169. this.push(serve(root, options))
  170. }
  171. return this
  172. }
  173. /* serve directory index */
  174. addIndex (path, options) {
  175. path = this.options.server.directory || path || process.cwd()
  176. options = Object.assign({ icons: true, hidden: true }, options)
  177. if (path) {
  178. const serveIndex = require('koa-serve-index')
  179. this.push(serveIndex(path, options))
  180. }
  181. return this
  182. }
  183. getMiddleware (options) {
  184. const compose = require('koa-compose')
  185. const convert = require('koa-convert')
  186. const middlewareStack = this.map(convert)
  187. return compose(middlewareStack)
  188. }
  189. }
  190. module.exports = MiddlewareStack