source_files.js 2.21 KB
Newer Older
jatuporn Tonggasem's avatar
jatuporn Tonggasem committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
var from = require('core-js/library/fn/array/from')
var querystring = require('querystring')
var _ = require('lodash')

var common = require('./common')
var logger = require('../logger')
var log = logger.create('middleware:source-files')

// Files is a Set
var findByPath = function (files, path) {
  return _.find(from(files), function (file) {
    return file.path === path
  })
}

var composeUrl = function (url, basePath, urlRoot, mustEscape) {
  return (mustEscape ? querystring.unescape(url) : url)
            .replace(urlRoot, '/')
            .replace(/\?.*$/, '')
            .replace(/^\/absolute/, '')
            .replace(/^\/base/, basePath)
}

// Source Files middleware is responsible for serving all the source files under the test.
var createSourceFilesMiddleware = function (filesPromise, serveFile, basePath, urlRoot) {
  return function (request, response, next) {
    var requestedFilePath = composeUrl(request.url, basePath, urlRoot, true)
    // When a path contains HTML-encoded characters (e.g %2F used by Jenkins for branches with /)
    var requestedFilePathUnescaped = composeUrl(request.url, basePath, urlRoot, false)

    request.pause()

    log.debug('Requesting %s', request.url, urlRoot)
    log.debug('Fetching %s', requestedFilePath)

    return filesPromise.then(function (files) {
      // TODO(vojta): change served to be a map rather then an array
      var file = findByPath(files.served, requestedFilePath) ||
                 findByPath(files.served, requestedFilePathUnescaped)
      var rangeHeader = request.headers['range']

      if (file) {
        serveFile(file.contentPath || file.path, rangeHeader, response, function () {
          if (/\?\w+/.test(request.url)) {
            // files with timestamps - cache one year, rely on timestamps
            common.setHeavyCacheHeaders(response)
          } else {
            // without timestamps - no cache (debug)
            common.setNoCacheHeaders(response)
          }
        }, file.content, file.doNotCache)
      } else {
        next()
      }

      request.resume()
    })
  }
}

createSourceFilesMiddleware.$inject = [
  'filesPromise', 'serveFile', 'config.basePath', 'config.urlRoot'
]

// PUBLIC API
exports.create = createSourceFilesMiddleware