web-server.js 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. 'use strict'
  2. const fs = require('graceful-fs')
  3. const http = require('http')
  4. const https = require('https')
  5. const path = require('path')
  6. const connect = require('connect')
  7. const Promise = require('bluebird')
  8. const common = require('./middleware/common')
  9. const runnerMiddleware = require('./middleware/runner')
  10. const stopperMiddleware = require('./middleware/stopper')
  11. const karmaMiddleware = require('./middleware/karma')
  12. const sourceFilesMiddleware = require('./middleware/source_files')
  13. const proxyMiddleware = require('./middleware/proxy')
  14. const log = require('./logger').create('web-server')
  15. function createCustomHandler (customFileHandlers, config) {
  16. return function (request, response, next) {
  17. const handler = customFileHandlers.find((handler) => handler.urlRegex.test(request.url))
  18. return handler
  19. ? handler.handler(request, response, 'fake/static', 'fake/adapter', config.basePath, 'fake/root')
  20. : next()
  21. }
  22. }
  23. createCustomHandler.$inject = ['customFileHandlers', 'config']
  24. function createFilesPromise (emitter, fileList) {
  25. const filesPromise = new common.PromiseContainer()
  26. // Set an empty list of files to avoid race issues with
  27. // file_list_modified not having been emitted yet
  28. filesPromise.set(Promise.resolve(fileList.files))
  29. emitter.on('file_list_modified', (files) => filesPromise.set(Promise.resolve(files)))
  30. return filesPromise
  31. }
  32. // Bind the filesystem into the injectable file reader function
  33. function createReadFilePromise () {
  34. return (filepath) => {
  35. return new Promise((resolve, reject) => {
  36. fs.readFile(filepath, 'utf8', function (error, data) {
  37. if (error) {
  38. reject(new Error(`Cannot read ${filepath}, got: ${error}`))
  39. } else if (!data) {
  40. reject(new Error(`No content at ${filepath}`))
  41. } else {
  42. resolve(data.split('\n'))
  43. }
  44. })
  45. })
  46. }
  47. }
  48. createReadFilePromise.$inject = []
  49. function createServeStaticFile (config) {
  50. return common.createServeFile(fs, path.normalize(path.join(__dirname, '/../static')), config)
  51. }
  52. createServeStaticFile.$inject = ['config']
  53. function createServeFile (config) {
  54. return common.createServeFile(fs, null, config)
  55. }
  56. createServeFile.$inject = ['config']
  57. function createWebServer (injector, config) {
  58. common.initializeMimeTypes(config)
  59. const proxyMiddlewareInstance = injector.invoke(proxyMiddleware.create)
  60. log.debug('Instantiating middleware')
  61. const handler = connect()
  62. if (config.beforeMiddleware) {
  63. config.beforeMiddleware.forEach((middleware) => handler.use(injector.get('middleware:' + middleware)))
  64. }
  65. handler.use(injector.invoke(runnerMiddleware.create))
  66. handler.use(injector.invoke(stopperMiddleware.create))
  67. handler.use(injector.invoke(karmaMiddleware.create))
  68. handler.use(injector.invoke(sourceFilesMiddleware.create))
  69. // TODO(vojta): extract the proxy into a plugin
  70. handler.use(proxyMiddlewareInstance)
  71. // TODO(vojta): remove, this is only here because of karma-dart
  72. // we need a better way of custom handlers
  73. handler.use(injector.invoke(createCustomHandler))
  74. if (config.middleware) {
  75. config.middleware.forEach((middleware) => handler.use(injector.get('middleware:' + middleware)))
  76. }
  77. handler.use((request, response) => common.serve404(response, request.url))
  78. let serverClass = http
  79. const serverArguments = [handler]
  80. if (config.protocol === 'https:') {
  81. serverClass = https
  82. serverArguments.unshift(config.httpsServerOptions || {})
  83. }
  84. if (config.httpModule) {
  85. serverClass = config.httpModule
  86. }
  87. const server = serverClass.createServer.apply(null, serverArguments)
  88. server.on('upgrade', function (req, socket, head) {
  89. log.debug(`upgrade ${req.url}`)
  90. proxyMiddlewareInstance.upgrade(req, socket, head)
  91. })
  92. return server
  93. }
  94. createWebServer.$inject = ['injector', 'config']
  95. module.exports = {
  96. createWebServer,
  97. createServeFile,
  98. createServeStaticFile,
  99. createFilesPromise,
  100. createReadFilePromise
  101. }