123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159 |
- /**
- * This module contains some common helpers shared between middlewares
- */
- var mime = require('mime')
- var _ = require('lodash')
- var parseRange = require('range-parser')
- var Buffer = require('safe-buffer').Buffer
- var log = require('../logger').create('web-server')
- var PromiseContainer = function () {
- var promise
- this.then = function (success, error) {
- error = error || _.noop
- return promise.then(success).catch(error)
- }
- this.set = function (newPromise) {
- promise = newPromise
- }
- }
- var serve404 = function (response, path) {
- log.warn('404: ' + path)
- response.writeHead(404)
- return response.end('NOT FOUND')
- }
- var createServeFile = function (fs, directory, config) {
- var cache = Object.create(null)
- return function (filepath, rangeHeader, response, transform, content, doNotCache) {
- var responseData
- var convertForRangeRequest = function () {
- var range = parseRange(responseData.length, rangeHeader)
- if (range === -2) {
- // malformed header string
- return 200
- } else if (range === -1) {
- // unsatisfiable range
- responseData = Buffer.alloc(0)
- return 416
- } else if (range.type === 'bytes') {
- responseData = Buffer.from(responseData)
- if (range.length === 1) {
- var start = range[0].start
- var end = range[0].end
- response.setHeader(
- 'Content-Range',
- 'bytes ' + start + '-' + end + '/' + responseData.length
- )
- response.setHeader('Accept-Ranges', 'bytes')
- response.setHeader('Content-Length', end - start + 1)
- responseData = responseData.slice(start, end + 1)
- return 206
- } else {
- // Multiple ranges are not supported. Maybe future?
- responseData = Buffer.alloc(0)
- return 416
- }
- }
- // All other states, ignore
- return 200
- }
- if (directory) {
- filepath = directory + filepath
- }
- if (!content && cache[filepath]) {
- content = cache[filepath]
- }
- if (config && config.customHeaders && config.customHeaders.length > 0) {
- config.customHeaders.forEach(function (header) {
- var regex = new RegExp(header.match)
- if (regex.test(filepath)) {
- log.debug('setting header: ' + header.name + ' for: ' + filepath)
- response.setHeader(header.name, header.value)
- }
- })
- }
- // serve from cache
- if (content && !doNotCache) {
- response.setHeader('Content-Type', mime.lookup(filepath, 'text/plain'))
- // call custom transform fn to transform the data
- responseData = (transform && transform(content)) || content
- if (rangeHeader) {
- var code = convertForRangeRequest()
- response.writeHead(code)
- } else {
- response.writeHead(200)
- }
- log.debug('serving (cached): ' + filepath)
- return response.end(responseData)
- }
- return fs.readFile(filepath, function (error, data) {
- if (error) {
- return serve404(response, filepath)
- }
- if (!doNotCache) {
- cache[filepath] = data.toString()
- }
- response.setHeader('Content-Type', mime.lookup(filepath, 'text/plain'))
- // call custom transform fn to transform the data
- responseData = (transform && transform(data.toString())) || data
- if (rangeHeader) {
- var code = convertForRangeRequest()
- response.writeHead(code)
- } else {
- response.writeHead(200)
- }
- log.debug('serving: ' + filepath)
- return response.end(responseData)
- })
- }
- }
- var setNoCacheHeaders = function (response) {
- response.setHeader('Cache-Control', 'no-cache')
- response.setHeader('Pragma', 'no-cache')
- response.setHeader('Expires', (new Date(0)).toUTCString())
- }
- var setHeavyCacheHeaders = function (response) {
- response.setHeader('Cache-Control', 'public, max-age=31536000')
- }
- var initializeMimeTypes = function (config) {
- if (config && config.mime) {
- _.forEach(config.mime, function (value, key) {
- var map = {}
- map[key] = value
- mime.define(map)
- })
- }
- }
- // PUBLIC API
- exports.PromiseContainer = PromiseContainer
- exports.createServeFile = createServeFile
- exports.setNoCacheHeaders = setNoCacheHeaders
- exports.setHeavyCacheHeaders = setHeavyCacheHeaders
- exports.initializeMimeTypes = initializeMimeTypes
- exports.serve404 = serve404
|