source_files.js 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667
  1. 'use strict'
  2. const querystring = require('querystring')
  3. const common = require('./common')
  4. const log = require('../logger').create('middleware:source-files')
  5. function findByPath (files, path) {
  6. return Array.from(files).find((file) => file.path === path)
  7. }
  8. function composeUrl (url, basePath, urlRoot) {
  9. return url
  10. .replace(urlRoot, '/')
  11. .replace(/\?.*$/, '')
  12. .replace(/^\/absolute/, '')
  13. .replace(/^\/base/, basePath)
  14. }
  15. // Source Files middleware is responsible for serving all the source files under the test.
  16. function createSourceFilesMiddleware (filesPromise, serveFile, basePath, urlRoot) {
  17. return function (request, response, next) {
  18. const requestedFilePath = composeUrl(request.url, basePath, urlRoot)
  19. // When a path contains HTML-encoded characters (e.g %2F used by Jenkins for branches with /)
  20. const requestedFilePathUnescaped = composeUrl(querystring.unescape(request.url), basePath, urlRoot)
  21. request.pause()
  22. log.debug(`Requesting ${request.url}`)
  23. log.debug(`Fetching ${requestedFilePath}`)
  24. return filesPromise.then(function (files) {
  25. // TODO(vojta): change served to be a map rather then an array
  26. const file = findByPath(files.served, requestedFilePath) || findByPath(files.served, requestedFilePathUnescaped)
  27. const rangeHeader = request.headers.range
  28. if (file) {
  29. const acceptEncodingHeader = request.headers['accept-encoding']
  30. const matchedEncoding = Object.keys(file.encodings).find(
  31. (encoding) => new RegExp(`(^|.*, ?)${encoding}(,|$)`).test(acceptEncodingHeader)
  32. )
  33. const content = file.encodings[matchedEncoding] || file.content
  34. serveFile(file.contentPath || file.path, rangeHeader, response, function () {
  35. if (/\?\w+/.test(request.url)) {
  36. common.setHeavyCacheHeaders(response) // files with timestamps - cache one year, rely on timestamps
  37. } else {
  38. common.setNoCacheHeaders(response) // without timestamps - no cache (debug)
  39. }
  40. if (matchedEncoding) {
  41. response.setHeader('Content-Encoding', matchedEncoding)
  42. }
  43. }, content, file.doNotCache)
  44. } else {
  45. next()
  46. }
  47. request.resume()
  48. })
  49. }
  50. }
  51. createSourceFilesMiddleware.$inject = [
  52. 'filesPromise', 'serveFile', 'config.basePath', 'config.urlRoot'
  53. ]
  54. exports.create = createSourceFilesMiddleware