Comparing version 4.1.0 to 4.2.0
@@ -5,3 +5,2 @@ 'use strict'; | ||
const Fs = require('fs'); | ||
const Crypto = require('crypto'); | ||
@@ -15,3 +14,5 @@ const Boom = require('boom'); | ||
const internals = {}; | ||
const internals = { | ||
pendings: Object.create(null) | ||
}; | ||
@@ -38,5 +39,3 @@ | ||
const pendings = response.request.server.plugins.inert._pendings; | ||
const pendingsId = '+' + cachekey; // Prefix to avoid conflicts with JS internals (e.g. __proto__) | ||
let nexts = pendings[pendingsId]; | ||
let nexts = internals.pendings[cachekey]; | ||
if (nexts) { | ||
@@ -49,3 +48,3 @@ return nexts.push(next); | ||
nexts = [next]; | ||
pendings[pendingsId] = nexts; | ||
internals.pendings[cachekey] = nexts; | ||
@@ -60,3 +59,3 @@ internals.hashFile(response, (err, hash) => { | ||
delete pendings[pendingsId]; | ||
delete internals.pendings[cachekey]; | ||
for (let i = 0; i < nexts.length; ++i) { | ||
@@ -74,3 +73,3 @@ Hoek.nextTick(nexts[i])(err, hash); | ||
const fileStream = Fs.createReadStream(response.source.path, { fd: response.source.fd, autoClose: false }); | ||
const fileStream = response.source.file.createReadStream({ autoClose: false }); | ||
fileStream.pipe(hash); | ||
@@ -77,0 +76,0 @@ |
113
lib/file.js
@@ -5,3 +5,2 @@ 'use strict'; | ||
const Fs = require('fs'); | ||
const Path = require('path'); | ||
@@ -13,2 +12,3 @@ const Ammo = require('ammo'); | ||
const Etag = require('./etag'); | ||
const Fs = require('./fs'); | ||
@@ -36,3 +36,5 @@ | ||
lookupMap: Joi.object().min(1).pattern(/.+/, Joi.string()), | ||
etagMethod: Joi.string().valid('hash', 'simple').allow(false) | ||
etagMethod: Joi.string().valid('hash', 'simple').allow(false), | ||
start: Joi.number().integer().min(0).default(0), | ||
end: Joi.number().integer().min(Joi.ref('start')) | ||
}) | ||
@@ -88,3 +90,3 @@ .with('filename', 'mode') | ||
stat: null, | ||
fd: null | ||
file: null | ||
}; | ||
@@ -109,4 +111,6 @@ | ||
internals.openStat(path, 'r', (err, fd, stat) => { | ||
const file = response.source.file = new Fs.File(path); | ||
file.openStat('r', (err, stat) => { | ||
if (err) { | ||
@@ -116,4 +120,9 @@ return callback(err); | ||
response.source.fd = fd; | ||
response.bytes(stat.size); | ||
const start = response.source.settings.start || 0; | ||
if (response.source.settings.end !== undefined) { | ||
response.bytes(response.source.settings.end - start + 1); | ||
} | ||
else { | ||
response.bytes(stat.size - start); | ||
} | ||
@@ -147,2 +156,4 @@ if (!response.headers['content-type']) { | ||
if (response.source.settings.lookupCompressed && | ||
!response.source.settings.start && | ||
response.source.settings.end === undefined && | ||
response.request.connection.settings.compression) { | ||
@@ -154,17 +165,15 @@ | ||
if (extension) { | ||
const gzFile = `${response.source.path}${extension}`; | ||
return internals.openStat(gzFile, 'r', (err, fd, stat) => { | ||
const gzFile = new Fs.File(`${response.source.path}${extension}`); | ||
return gzFile.openStat('r', (err, stat) => { | ||
if (err) { | ||
return internals.openStream(response, response.source.path, next); | ||
if (!err) { | ||
response.source.file.close(); | ||
response.source.file = gzFile; | ||
response.bytes(stat.size); | ||
response.header('content-encoding', encoding); | ||
response.vary('accept-encoding'); | ||
} | ||
internals.close(response); | ||
response.source.fd = fd; | ||
response.bytes(stat.size); | ||
response.header('content-encoding', encoding); | ||
response.vary('accept-encoding'); | ||
return internals.openStream(response, gzFile, next); | ||
return internals.createStream(response, next); | ||
}); | ||
@@ -174,7 +183,7 @@ } | ||
return internals.openStream(response, response.source.path, next); | ||
return internals.createStream(response, next); | ||
}; | ||
internals.addContentRange = function (response, callback) { | ||
internals.addContentRange = function (response, next) { | ||
@@ -206,3 +215,3 @@ const request = response.request; | ||
error.output.headers['content-range'] = 'bytes */' + length; | ||
return callback(error); | ||
return next(error); | ||
} | ||
@@ -225,11 +234,11 @@ | ||
return callback(null, range); | ||
return next(null, range); | ||
}; | ||
internals.openStream = function (response, path, next) { | ||
internals.createStream = function (response, next) { | ||
Hoek.assert(response.source.fd !== null, 'file descriptor must be set'); | ||
const source = response.source; | ||
const options = { fd: response.source.fd, start: 0 }; | ||
Hoek.assert(source.file !== null); | ||
@@ -242,11 +251,13 @@ internals.addContentRange(response, (err, range) => { | ||
const options = { | ||
start: source.settings.start || 0, | ||
end: source.settings.end | ||
}; | ||
if (range) { | ||
options.start = range.from; | ||
options.end = range.to; | ||
options.end = range.to + options.start; | ||
options.start = range.from + options.start; | ||
} | ||
const fileStream = Fs.createReadStream(path, options); | ||
response.source.fd = null; // Claim descriptor | ||
return next(null, fileStream); | ||
return next(null, source.file.createReadStream(options)); | ||
}); | ||
@@ -256,42 +267,8 @@ }; | ||
internals.openStat = function (path, mode, callback) { | ||
Fs.open(path, mode, (err, fd) => { | ||
if (err) { | ||
if (path.indexOf('\u0000') !== -1 || err.code === 'ENOENT') { | ||
return callback(Boom.notFound()); | ||
} | ||
if (err.code === 'EACCES' || err.code === 'EPERM') { | ||
return callback(Boom.forbidden(null, err.code)); | ||
} | ||
return callback(Boom.wrap(err, null, 'Failed to open file')); | ||
} | ||
Fs.fstat(fd, (err, stat) => { | ||
if (err) { | ||
Fs.close(fd, Hoek.ignore); | ||
return callback(Boom.wrap(err, null, 'Failed to stat file')); | ||
} | ||
if (stat.isDirectory()) { | ||
Fs.close(fd, Hoek.ignore); | ||
return callback(Boom.forbidden(null, 'EISDIR')); | ||
} | ||
return callback(null, fd, stat); | ||
}); | ||
}); | ||
}; | ||
internals.close = function (response) { | ||
if (response.source.fd !== null) { | ||
Fs.close(response.source.fd, Hoek.ignore); | ||
response.source.fd = null; | ||
if (response.source.file !== null) { | ||
response.source.file.close(); | ||
response.source.file = null; | ||
} | ||
}; |
@@ -25,3 +25,2 @@ 'use strict'; | ||
server.expose('_etags', settings.etagsCacheMaxSize ? new Etag.Cache(settings.etagsCacheMaxSize) : null); | ||
server.expose('_pendings', {}); | ||
@@ -36,2 +35,3 @@ server.handler('file', File.handler); | ||
responseOptions = responseOptions || {}; | ||
if (typeof responseOptions.confine === 'undefined' || responseOptions.confine === true) { | ||
@@ -41,2 +41,4 @@ responseOptions.confine = '.'; | ||
Hoek.assert(responseOptions.end === undefined || +responseOptions.start <= +responseOptions.end, 'options.start must be less than or equal to options.end'); | ||
return this.response(File.response(path, responseOptions, this.request)); | ||
@@ -43,0 +45,0 @@ }); |
{ | ||
"name": "inert", | ||
"description": "Static file and directory handlers plugin for hapi.js", | ||
"version": "4.1.0", | ||
"version": "4.2.0", | ||
"repository": "git://github.com/hapijs/inert", | ||
@@ -28,3 +28,3 @@ "main": "lib/index.js", | ||
"hapi": "16.x.x", | ||
"lab": "11.x.x" | ||
"lab": "13.x.x" | ||
}, | ||
@@ -31,0 +31,0 @@ "scripts": { |
@@ -172,2 +172,4 @@ # inert | ||
- `false` - Disable ETag computation. | ||
- `start` - offset in file to reading from, defaults to 0. | ||
- `end` - offset in file to stop reading from. If not set, will read to end of file. | ||
@@ -211,2 +213,4 @@ Returns a standard [response](https://github.com/hapijs/hapi/blob/master/API.md#response-object) object. | ||
- `false` - Disable ETag computation. | ||
- `start` - offset in file to reading from, defaults to 0. | ||
- `end` - offset in file to stop reading from. If not set, will read to end of file. | ||
@@ -213,0 +217,0 @@ ### The `directory` handler |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
35075
9
533
260
3