Comparing version 0.6.0 to 0.7.0
@@ -0,1 +1,13 @@ | ||
0.7.0 / 2014-07-20 | ||
================== | ||
* Deprecate `hidden` option; use `dotfiles` option | ||
* Add `dotfiles` option | ||
* deps: debug@1.0.4 | ||
* deps: depd@0.4.2 | ||
- Add `TRACE_DEPRECATION` environment variable | ||
- Remove non-standard grey color from color output | ||
- Support `--no-deprecation` argument | ||
- Support `--trace-deprecation` argument | ||
0.6.0 / 2014-07-11 | ||
@@ -10,2 +22,3 @@ ================== | ||
* Deprecate `send.root()` -- use `root` in `options` | ||
* Cap `maxAge` value to 1 year | ||
* deps: debug@1.0.3 | ||
@@ -12,0 +25,0 @@ - Add support for multiple wildcards in namespaces |
137
lib/send.js
@@ -17,3 +17,2 @@ | ||
, fs = require('fs') | ||
, basename = path.basename | ||
, normalize = path.normalize | ||
@@ -29,3 +28,5 @@ , join = path.join | ||
var maxMaxAge = 60 * 60 * 24 * 365 * 1000; // 1 year | ||
var upPathRegexp = /(?:^|[\\\/])\.\.(?:[\\\/]|$)/; | ||
var resolve = path.resolve | ||
var sep = path.sep | ||
var upPathRegexp = /(?:^|[\\\/])\.\.(?:[\\\/]|$)/ | ||
@@ -69,9 +70,2 @@ /** | ||
* | ||
* Events: | ||
* | ||
* - `error` an error occurred | ||
* - `stream` file streaming has started | ||
* - `end` streaming has completed | ||
* - `directory` a directory was requested | ||
* | ||
* @param {Request} req | ||
@@ -94,4 +88,21 @@ * @param {String} path | ||
this._dotfiles = options.dotfiles !== undefined | ||
? options.dotfiles | ||
: 'ignore' | ||
if (['allow', 'deny', 'ignore'].indexOf(this._dotfiles) === -1) { | ||
throw new TypeError('dotfiles option must be "allow", "deny", or "ignore"') | ||
} | ||
this._hidden = Boolean(options.hidden) | ||
if ('hidden' in options) { | ||
deprecate('hidden: use dotfiles: \'' + (this._hidden ? 'allow' : 'ignore') + '\' instead') | ||
} | ||
// legacy support | ||
if (!('dotfiles' in options)) { | ||
this._dotfiles = undefined | ||
} | ||
this._index = options.index !== undefined | ||
@@ -110,3 +121,3 @@ ? normalizeIndex(options.index) | ||
this._root = options.root | ||
? normalize(options.root) | ||
? resolve(options.root) | ||
: null | ||
@@ -152,4 +163,5 @@ | ||
this._hidden = val; | ||
this._dotfiles = undefined | ||
return this; | ||
}, 'send.hidden: pass hidden as option'); | ||
}, 'send.hidden: use dotfiles option'); | ||
@@ -182,3 +194,3 @@ /** | ||
path = String(path); | ||
this._root = normalize(path); | ||
this._root = resolve(path) | ||
return this; | ||
@@ -239,13 +251,2 @@ }; | ||
/** | ||
* Check if the pathname is potentially malicious. | ||
* | ||
* @return {Boolean} | ||
* @api private | ||
*/ | ||
SendStream.prototype.isMalicious = function(){ | ||
return !this._root && ~this.path.indexOf('..') && upPathRegexp.test(this.path); | ||
}; | ||
/** | ||
* Check if the pathname ends with "/". | ||
@@ -262,13 +263,2 @@ * | ||
/** | ||
* Check if the basename leads with ".". | ||
* | ||
* @return {Boolean} | ||
* @api private | ||
*/ | ||
SendStream.prototype.hasLeadingDot = function(){ | ||
return '.' == basename(this.path)[0]; | ||
}; | ||
/** | ||
* Check if this is a conditional GET request. | ||
@@ -412,3 +402,2 @@ * | ||
, args = arguments | ||
, path = this.path | ||
, root = this._root; | ||
@@ -419,5 +408,5 @@ | ||
// invalid request uri | ||
path = utils.decode(path); | ||
if (-1 == path) return this.error(400); | ||
// decode the path | ||
var path = utils.decode(this.path) | ||
if (path === -1) return this.error(400) | ||
@@ -427,14 +416,52 @@ // null byte(s) | ||
// join / normalize from optional root dir | ||
if (root) path = normalize(join(this._root, path)); | ||
var parts | ||
if (root !== null) { | ||
// join / normalize from optional root dir | ||
path = normalize(join(root, path)) | ||
// ".." is malicious without "root" | ||
if (this.isMalicious()) return this.error(403); | ||
// malicious path | ||
if (path.substr(0, root.length) !== root) { | ||
debug('malicious path "%s"', path) | ||
return this.error(403) | ||
} | ||
// malicious path | ||
if (root && 0 != path.indexOf(root)) return this.error(403); | ||
// explode path parts | ||
parts = path.substr(root.length + 1).split(sep) | ||
} else { | ||
// ".." is malicious without "root" | ||
if (upPathRegexp.test(path)) { | ||
debug('malicious path "%s"', path) | ||
return this.error(403) | ||
} | ||
// hidden file support | ||
if (!this._hidden && this.hasLeadingDot()) return this.error(404); | ||
// explode path parts | ||
parts = normalize(path).split(sep) | ||
// resolve the path | ||
path = resolve(path) | ||
} | ||
// dotfile handling | ||
if (containsDotFile(parts)) { | ||
var access = this._dotfiles | ||
// legacy support | ||
if (access === undefined) { | ||
access = parts[parts.length - 1][0] === '.' | ||
? (this._hidden ? 'allow' : 'ignore') | ||
: 'allow' | ||
} | ||
debug('%s dotfile "%s"', access, path) | ||
switch (access) { | ||
case 'allow': | ||
break | ||
case 'deny': | ||
return this.error(403) | ||
case 'ignore': | ||
default: | ||
return this.error(404) | ||
} | ||
} | ||
// index file support | ||
@@ -477,3 +504,3 @@ if (this._index.length && this.hasTrailingSlash()) { | ||
debug('options %o', options); | ||
debug('pipe "%s"', path) | ||
@@ -673,2 +700,18 @@ // set header fields | ||
/** | ||
* Determine if path parts contain a dotfile. | ||
* | ||
* @api private | ||
*/ | ||
function containsDotFile(parts) { | ||
for (var i = 0; i < parts.length; i++) { | ||
if (parts[i][0] === '.') { | ||
return true | ||
} | ||
} | ||
return false | ||
} | ||
/** | ||
* Normalize the index option into an array. | ||
@@ -675,0 +718,0 @@ * |
{ | ||
"name": "send", | ||
"description": "Better streaming static file server with Range and conditional-GET support", | ||
"version": "0.6.0", | ||
"version": "0.7.0", | ||
"author": "TJ Holowaychuk <tj@vision-media.ca>", | ||
@@ -17,4 +17,4 @@ "contributors": [ | ||
"dependencies": { | ||
"debug": "1.0.3", | ||
"depd": "0.3.0", | ||
"debug": "1.0.4", | ||
"depd": "0.4.2", | ||
"escape-html": "1.0.1", | ||
@@ -37,6 +37,6 @@ "finished": "1.2.2", | ||
"scripts": { | ||
"test": "mocha --reporter dot", | ||
"test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --reporter dot", | ||
"test-travis": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --reporter spec" | ||
"test": "mocha --check-leaks --reporter spec --bail", | ||
"test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --check-leaks --reporter dot", | ||
"test-travis": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --check-leaks --reporter spec" | ||
} | ||
} |
@@ -72,6 +72,17 @@ # send | ||
#### hidden | ||
#### dotfiles | ||
Enable or disable transfer of hidden files, defaults to false. | ||
Set how "dotfiles" are treated when encountered. A dotfile is a file | ||
or directory that begins with a dot ("."). Note this check is done on | ||
the path itself without checking if the path actually exists on the | ||
disk. If `root` is specified, only the dotfiles above the root are | ||
checked (i.e. the root itself can be within a dotfile when when set | ||
to "deny"). | ||
The default value is `'ignore'`. | ||
- `'allow'` No special treatment for dotfiles. | ||
- `'deny'` Send a 403 for any request for a dotfile. | ||
- `'ignore'` Pretend like the dotfile does not exist and 404. | ||
#### index | ||
@@ -78,0 +89,0 @@ |
24959
622
160
+ Addeddebug@1.0.4(transitive)
+ Addeddepd@0.4.2(transitive)
- Removeddebug@1.0.3(transitive)
- Removeddepd@0.3.0(transitive)
Updateddebug@1.0.4
Updateddepd@0.4.2