diff --git a/lib/file.js b/lib/file.js index 094df9e0e..8689db103 100644 --- a/lib/file.js +++ b/lib/file.js @@ -14,6 +14,10 @@ class File { // where the content is stored (processed) this.contentPath = path + // encodings format {[encodingType]: encodedContent} + // example: {gzip: } + this.encodings = Object.create(null) + this.mtime = mtime this.isUrl = false diff --git a/lib/middleware/source_files.js b/lib/middleware/source_files.js index 5fd236ccd..efe1f4a29 100644 --- a/lib/middleware/source_files.js +++ b/lib/middleware/source_files.js @@ -35,13 +35,22 @@ function createSourceFilesMiddleware (filesPromise, serveFile, basePath, urlRoot const rangeHeader = request.headers['range'] if (file) { + const acceptEncodingHeader = request.headers['accept-encoding'] + const matchedEncoding = Object.keys(file.encodings).find( + (encoding) => new RegExp(`(^|.*, ?)${encoding}(,|$)`).test(acceptEncodingHeader) + ) + const content = file.encodings[matchedEncoding] || file.content + serveFile(file.contentPath || file.path, rangeHeader, response, function () { if (/\?\w+/.test(request.url)) { common.setHeavyCacheHeaders(response) // files with timestamps - cache one year, rely on timestamps } else { common.setNoCacheHeaders(response) // without timestamps - no cache (debug) } - }, file.content, file.doNotCache) + if (matchedEncoding) { + response.setHeader('Content-Encoding', matchedEncoding) + } + }, content, file.doNotCache) } else { next() } diff --git a/test/unit/middleware/source_files.spec.js b/test/unit/middleware/source_files.spec.js index 540e9cf0b..5dbfffb83 100644 --- a/test/unit/middleware/source_files.spec.js +++ b/test/unit/middleware/source_files.spec.js @@ -1,6 +1,7 @@ var http = require('http') var mocks = require('mocks') var request = require('supertest') +var zlib = require('zlib') var helper = require('../../../lib/helper') var File = require('../../../lib/file') @@ -109,6 +110,42 @@ describe('middleware.source_files', function () { }) }) + describe('file encoding', function () { + let file + beforeEach(function () { + file = new File('/src/some.js') + servedFiles([ + file + ]) + }) + + it('serves gzip encoded files properly', function () { + file.encodings.gzip = zlib.gzipSync('gzipped-js-source') + return request(server) + .get('/absolute/src/some.js') + .set('Accept-Encoding', 'gzip, deflate') + .expect(200, 'gzipped-js-source') + .expect('Content-Encoding', 'gzip') + .expect('Content-Type', 'application/javascript') + }) + + it('serves unencoded files when request does not accept available encodings', function (done) { + file.encodings.gzip = zlib.gzipSync('gzipped-js-source') + request(server) + .get('/absolute/src/some.js') + .set('Accept-Encoding', 'gzippy, deflate') + .expect(200, 'js-source') + .end((error, res) => { + if (error) { + return done(error) + } + // expect(Object.keys(res.headers)).to.not.include('content-encoding') + expect(res.headers).to.not.have.property('content-encoding') + return done() + }) + }) + }) + it('should serve absolute js source files ignoring timestamp', function () { servedFiles([ new File('/src/some.js')