'use strict' const fs = require('graceful-fs') const http = require('http') const https = require('https') const path = require('path') const connect = require('connect') const Promise = require('bluebird') const common = require('./middleware/common') const runnerMiddleware = require('./middleware/runner') const stopperMiddleware = require('./middleware/stopper') const karmaMiddleware = require('./middleware/karma') const sourceFilesMiddleware = require('./middleware/source_files') const proxyMiddleware = require('./middleware/proxy') const log = require('./logger').create('web-server') function createCustomHandler (customFileHandlers, config) { return function (request, response, next) { const handler = customFileHandlers.find((handler) => handler.urlRegex.test(request.url)) return handler ? handler.handler(request, response, 'fake/static', 'fake/adapter', config.basePath, 'fake/root') : next() } } createCustomHandler.$inject = ['customFileHandlers', 'config'] function createFilesPromise (emitter, fileList) { const filesPromise = new common.PromiseContainer() // Set an empty list of files to avoid race issues with // file_list_modified not having been emitted yet filesPromise.set(Promise.resolve(fileList.files)) emitter.on('file_list_modified', (files) => filesPromise.set(Promise.resolve(files))) return filesPromise } // Bind the filesystem into the injectable file reader function function createReadFilePromise () { return (filepath) => { return new Promise((resolve, reject) => { fs.readFile(filepath, 'utf8', function (error, data) { if (error) { reject(new Error(`Cannot read ${filepath}, got: ${error}`)) } else if (!data) { reject(new Error(`No content at ${filepath}`)) } else { resolve(data.split('\n')) } }) }) } } createReadFilePromise.$inject = [] function createServeStaticFile (config) { return common.createServeFile(fs, path.normalize(path.join(__dirname, '/../static')), config) } createServeStaticFile.$inject = ['config'] function createServeFile (config) { return common.createServeFile(fs, null, config) } createServeFile.$inject = ['config'] function createWebServer (injector, config) { common.initializeMimeTypes(config) const proxyMiddlewareInstance = injector.invoke(proxyMiddleware.create) log.debug('Instantiating middleware') const handler = connect() if (config.beforeMiddleware) { config.beforeMiddleware.forEach((middleware) => handler.use(injector.get('middleware:' + middleware))) } handler.use(injector.invoke(runnerMiddleware.create)) handler.use(injector.invoke(stopperMiddleware.create)) handler.use(injector.invoke(karmaMiddleware.create)) handler.use(injector.invoke(sourceFilesMiddleware.create)) // TODO(vojta): extract the proxy into a plugin handler.use(proxyMiddlewareInstance) // TODO(vojta): remove, this is only here because of karma-dart // we need a better way of custom handlers handler.use(injector.invoke(createCustomHandler)) if (config.middleware) { config.middleware.forEach((middleware) => handler.use(injector.get('middleware:' + middleware))) } handler.use((request, response) => common.serve404(response, request.url)) let serverClass = http const serverArguments = [handler] if (config.protocol === 'https:') { serverClass = https serverArguments.unshift(config.httpsServerOptions || {}) } if (config.httpModule) { serverClass = config.httpModule } const server = serverClass.createServer.apply(null, serverArguments) server.on('upgrade', function (req, socket, head) { log.debug(`upgrade ${req.url}`) proxyMiddlewareInstance.upgrade(req, socket, head) }) return server } createWebServer.$inject = ['injector', 'config'] module.exports = { createWebServer, createServeFile, createServeStaticFile, createFilesPromise, createReadFilePromise }