Commit 77a29a30 authored by Leo Iannacone's avatar Leo Iannacone

update internal libraries

parent 0a65407c
......@@ -29,5 +29,5 @@
"url": "https://github.com/visionmedia/ejs/issues"
},
"_id": "ejs@1.0.0",
"_from": "ejs@>= 0.0.1"
"_from": "ejs@1.*"
}
......@@ -35,5 +35,5 @@
"url": "https://github.com/expressjs/accepts/issues"
},
"_id": "accepts@1.0.7",
"_from": "accepts@~1.0.4"
"_from": "accepts@~1.0.5"
}
4.6.1 / 2014-07-12
==================
* fix `subapp.mountpath` regression for `app.use(subapp)`
4.6.0 / 2014-07-11
==================
* accept multiple callbacks to `app.use()`
* add explicit "Rosetta Flash JSONP abuse" protection
- previous versions are not vulnerable; this is just explicit protection
* catch errors in multiple `req.param(name, fn)` handlers
* deprecate `res.redirect(url, status)` -- use `res.redirect(status, url)` instead
* fix `res.send(status, num)` to send `num` as json (not error)
* remove unnecessary escaping when `res.jsonp` returns JSON response
* support non-string `path` in `app.use(path, fn)`
- supports array of paths
- supports `RegExp`
* router: fix optimization on router exit
* router: refactor location of `try` blocks
* router: speed up standard `app.use(fn)`
* deps: debug@1.0.3
- Add support for multiple wildcards in namespaces
* deps: finalhandler@0.0.3
- deps: debug@1.0.3
* deps: methods@1.1.0
- add `CONNECT`
* deps: parseurl@~1.1.3
- faster parsing of href-only URLs
* deps: path-to-regexp@0.1.3
* deps: send@0.6.0
- deps: debug@1.0.3
* deps: serve-static@~1.3.2
- deps: parseurl@~1.1.3
- deps: send@0.6.0
* perf: fix arguments reassign deopt in some `res` methods
4.5.1 / 2014-07-06
==================
......@@ -237,6 +274,30 @@
- `app.route()` - Proxy to the app's `Router#route()` method to create a new route
- Router & Route - public API
3.14.0 / 2014-07-11
===================
* add explicit "Rosetta Flash JSONP abuse" protection
- previous versions are not vulnerable; this is just explicit protection
* deprecate `res.redirect(url, status)` -- use `res.redirect(status, url)` instead
* fix `res.send(status, num)` to send `num` as json (not error)
* remove unnecessary escaping when `res.jsonp` returns JSON response
* deps: basic-auth@1.0.0
- support empty password
- support empty username
* deps: connect@2.23.0
- deps: debug@1.0.3
- deps: express-session@~1.6.4
- deps: method-override@~2.1.0
- deps: parseurl@~1.1.3
- deps: serve-static@~1.3.1
* deps: debug@1.0.3
- Add support for multiple wildcards in namespaces
* deps: methods@1.1.0
- add `CONNECT`
* deps: parseurl@~1.1.3
- faster parsing of href-only URLs
3.13.0 / 2014-07-03
===================
......
[![Express Logo](https://i.cloudup.com/zfY6lL7eFa-3000x3000.png)](https://expressjs.com/)
Fast, unopinionated, minimalist web framework for [node](https://nodejs.org).
Fast, unopinionated, minimalist web framework for [node](http://nodejs.org).
[![NPM Version](https://badge.fury.io/js/express.svg)](https://badge.fury.io/js/express)
[![Build Status](https://travis-ci.org/visionmedia/express.svg?branch=master)](https://travis-ci.org/visionmedia/express)
......
......@@ -147,38 +147,49 @@ app.handle = function(req, res, done) {
* @api public
*/
app.use = function(route, fn){
app.use = function use(path, fn) {
var mount_app;
var mount_path;
// check for .use(path, app) or .use(app) signature
if (arguments.length <= 2) {
mount_path = typeof path === 'string'
? path
: '/';
mount_app = typeof path === 'function'
? path
: fn;
}
// default route to '/'
if ('string' != typeof route) fn = route, route = '/';
// setup router
this.lazyrouter();
var router = this._router;
// express app
if (fn.handle && fn.set) mount_app = fn;
if (mount_app && mount_app.handle && mount_app.set) {
debug('.use app under %s', mount_path);
mount_app.mountpath = mount_path;
mount_app.parent = this;
// restore .app property on req and res
if (mount_app) {
debug('.use app under %s', route);
mount_app.mountpath = route;
fn = function(req, res, next) {
// restore .app property on req and res
router.use(mount_path, function mounted_app(req, res, next) {
var orig = req.app;
mount_app.handle(req, res, function(err) {
req.__proto__ = orig.request;
res.__proto__ = orig.response;
next(err);
});
};
}
this.lazyrouter();
this._router.use(route, fn);
});
// mounted an app
if (mount_app) {
mount_app.parent = this;
// mounted an app
mount_app.emit('mount', this);
return this;
}
// pass-through use
router.use.apply(router, arguments);
return this;
};
......
......@@ -78,67 +78,77 @@ res.links = function(links){
* @api public
*/
res.send = function(body){
var req = this.req;
var head = 'HEAD' == req.method;
var type;
res.send = function send(body) {
var chunk = body;
var encoding;
var len;
var req = this.req;
var type;
// settings
var app = this.app;
// allow status / body
if (2 == arguments.length) {
if (arguments.length === 2) {
// res.send(body, status) backwards compat
if ('number' != typeof body && 'number' == typeof arguments[1]) {
if (typeof arguments[0] !== 'number' && typeof arguments[1] === 'number') {
deprecate('res.send(body, status): Use res.send(status, body) instead');
this.statusCode = arguments[1];
} else {
this.statusCode = body;
body = arguments[1];
this.statusCode = arguments[0];
chunk = arguments[1];
}
}
switch (typeof body) {
// response status
case 'number':
this.get('Content-Type') || this.type('txt');
this.statusCode = body;
body = http.STATUS_CODES[body];
break;
// disambiguate res.send(status) and res.send(status, num)
if (typeof chunk === 'number' && arguments.length === 1) {
// res.send(status) will set status message as text string
if (!this.get('Content-Type')) {
this.type('txt');
}
this.statusCode = chunk;
chunk = http.STATUS_CODES[chunk];
}
switch (typeof chunk) {
// string defaulting to html
case 'string':
if (!this.get('Content-Type')) this.type('html');
if (!this.get('Content-Type')) {
this.type('html');
}
break;
case 'boolean':
case 'number':
case 'object':
if (null == body) {
body = '';
} else if (Buffer.isBuffer(body)) {
this.get('Content-Type') || this.type('bin');
if (chunk === null) {
chunk = '';
} else if (Buffer.isBuffer(chunk)) {
if (!this.get('Content-Type')) {
this.type('bin');
}
} else {
return this.json(body);
return this.json(chunk);
}
break;
}
// write strings in utf-8
if ('string' === typeof body) {
if (typeof chunk === 'string') {
encoding = 'utf8';
type = this.get('Content-Type');
// reflect this in content-type
if ('string' === typeof type) {
if (typeof type === 'string') {
this.set('Content-Type', setCharset(type, 'utf-8'));
}
}
// populate Content-Length
if (undefined !== body && !this.get('Content-Length')) {
len = Buffer.isBuffer(body)
? body.length
: Buffer.byteLength(body, encoding);
if (chunk !== undefined && !this.get('Content-Length')) {
len = Buffer.isBuffer(chunk)
? chunk.length
: Buffer.byteLength(chunk, encoding);
this.set('Content-Length', len);
}
......@@ -146,7 +156,7 @@ res.send = function(body){
var etag = len !== undefined && app.get('etag fn');
if (etag && ('GET' === req.method || 'HEAD' === req.method)) {
if (!this.get('ETag')) {
etag = etag(body, encoding);
etag = etag(chunk, encoding);
etag && this.set('ETag', etag);
}
}
......@@ -159,11 +169,16 @@ res.send = function(body){
this.removeHeader('Content-Type');
this.removeHeader('Content-Length');
this.removeHeader('Transfer-Encoding');
body = '';
chunk = '';
}
// skip body for HEAD
if (req.method === 'HEAD') {
this.end();
}
// respond
this.end((head ? null : body), encoding);
this.end(chunk, encoding);
return this;
};
......@@ -181,20 +196,22 @@ res.send = function(body){
* @api public
*/
res.json = function(obj){
res.json = function json(obj) {
var val = obj;
// allow status / body
if (2 == arguments.length) {
if (arguments.length === 2) {
// res.json(body, status) backwards compat
if ('number' == typeof arguments[1]) {
if (typeof arguments[1] === 'number') {
this.statusCode = arguments[1];
if (typeof obj === 'number') {
if (typeof arguments[0] === 'number') {
deprecate('res.json(obj, status): Use res.json(status, obj) instead');
} else {
deprecate('res.json(num, status): Use res.status(status).json(num) instead');
}
} else {
this.statusCode = obj;
obj = arguments[1];
this.statusCode = arguments[0];
val = arguments[1];
}
}
......@@ -202,10 +219,12 @@ res.json = function(obj){
var app = this.app;
var replacer = app.get('json replacer');
var spaces = app.get('json spaces');
var body = JSON.stringify(obj, replacer, spaces);
var body = JSON.stringify(val, replacer, spaces);
// content-type
this.get('Content-Type') || this.set('Content-Type', 'application/json');
if (!this.get('Content-Type')) {
this.set('Content-Type', 'application/json');
}
return this.send(body);
};
......@@ -223,20 +242,22 @@ res.json = function(obj){
* @api public
*/
res.jsonp = function(obj){
res.jsonp = function jsonp(obj) {
var val = obj;
// allow status / body
if (2 == arguments.length) {
if (arguments.length === 2) {
// res.json(body, status) backwards compat
if ('number' == typeof arguments[1]) {
if (typeof arguments[1] === 'number') {
this.statusCode = arguments[1];
if (typeof obj === 'number') {
if (typeof arguments[0] === 'number') {
deprecate('res.jsonp(obj, status): Use res.jsonp(status, obj) instead');
} else {
deprecate('res.jsonp(num, status): Use res.status(status).jsonp(num) instead');
}
} else {
this.statusCode = obj;
obj = arguments[1];
this.statusCode = arguments[0];
val = arguments[1];
}
}
......@@ -244,13 +265,14 @@ res.jsonp = function(obj){
var app = this.app;
var replacer = app.get('json replacer');
var spaces = app.get('json spaces');
var body = JSON.stringify(obj, replacer, spaces)
.replace(/\u2028/g, '\\u2028')
.replace(/\u2029/g, '\\u2029');
var body = JSON.stringify(val, replacer, spaces);
var callback = this.req.query[app.get('jsonp callback name')];
// content-type
this.get('Content-Type') || this.set('Content-Type', 'application/json');
if (!this.get('Content-Type')) {
this.set('X-Content-Type-Options', 'nosniff');
this.set('Content-Type', 'application/json');
}
// fixup callback
if (Array.isArray(callback)) {
......@@ -258,10 +280,22 @@ res.jsonp = function(obj){
}
// jsonp
if (callback && 'string' === typeof callback) {
if (typeof callback === 'string' && callback.length !== 0) {
this.charset = 'utf-8';
this.set('X-Content-Type-Options', 'nosniff');
this.set('Content-Type', 'text/javascript');
var cb = callback.replace(/[^\[\]\w$.]/g, '');
body = 'typeof ' + cb + ' === \'function\' && ' + cb + '(' + body + ');';
// restrict callback charset
callback = callback.replace(/[^\[\]\w$.]/g, '');
// replace chars not allowed in JavaScript that are in JSON
body = body
.replace(/\u2028/g, '\\u2028')
.replace(/\u2029/g, '\\u2029');
// the /**/ is a specific security mitigation for "Rosetta Flash JSONP abuse"
// the typeof check is just to reduce client error noise
body = '/**/ typeof ' + callback + ' === \'function\' && ' + callback + '(' + body + ');';
}
return this.send(body);
......@@ -550,8 +584,8 @@ res.attachment = function(filename){
*/
res.set =
res.header = function(field, val){
if (2 == arguments.length) {
res.header = function header(field, val) {
if (arguments.length === 2) {
if (Array.isArray(val)) val = val.map(String);
else val = String(val);
if ('content-type' == field.toLowerCase() && !/;\s*charset\s*=/.test(val)) {
......@@ -687,32 +721,30 @@ res.location = function(url){
* res.redirect('/foo/bar');
* res.redirect('http://example.com');
* res.redirect(301, 'http://example.com');
* res.redirect('http://example.com', 301);
* res.redirect('../login'); // /blog/post/1 -> /blog/login
*
* @param {String} url
* @param {Number} code
* @api public
*/
res.redirect = function(url){
var head = 'HEAD' == this.req.method;
var status = 302;
res.redirect = function redirect(url) {
var address = url;
var body;
var status = 302;
// allow status / url
if (2 == arguments.length) {
if ('number' == typeof url) {
status = url;
url = arguments[1];
if (arguments.length === 2) {
if (typeof arguments[0] === 'number') {
status = arguments[0];
address = arguments[1];
} else {
deprecate('res.redirect(ur, status): Use res.redirect(status, url) instead');
status = arguments[1];
}
}
// Set location header
this.location(url);
url = this.get('Location');
this.location(address);
address = this.get('Location');
// Support text/{plain,html} by default
this.format({
......@@ -733,7 +765,12 @@ res.redirect = function(url){
// Respond
this.statusCode = status;
this.set('Content-Length', Buffer.byteLength(body));
this.end(head ? null : body);
if (this.req.method === 'HEAD') {
this.end();
}
this.end(body);
};
/**
......
......@@ -9,6 +9,8 @@ var mixin = require('utils-merge');
var debug = require('debug')('express:router');
var parseUrl = require('parseurl');
var slice = Array.prototype.slice;
var toString = Object.prototype.toString;
var utils = require('../utils');
/**
* Initialize a new `Router` with the given `options`.
......@@ -149,35 +151,38 @@ proto.handle = function(req, res, done) {
});
}
// setup basic req values
req.baseUrl = parentUrl;
req.originalUrl = req.originalUrl || req.url;
next();
function next(err) {
if (err === 'route') {
err = undefined;
}
var layerError = err === 'route'
? null
: err;
var layer = stack[idx++];
var layerPath;
if (!layer) {
return done(err);
}
if (slashAdded) {
req.url = req.url.substr(1);
slashAdded = false;
}
req.baseUrl = parentUrl;
req.url = protohost + removed + req.url.substr(protohost.length);
req.originalUrl = req.originalUrl || req.url;
removed = '';
if (removed.length !== 0) {
req.baseUrl = parentUrl;
req.url = protohost + removed + req.url.substr(protohost.length);
removed = '';
}
try {
var path = parseUrl(req).pathname;
if (undefined == path) path = '/';
if (!layer) {
return done(layerError);
}
if (!layer.match(path)) return next(err);
self.match_layer(layer, req, res, function (err, path) {
if (err || path === undefined) {
return next(layerError || err);
}
// route object and not middleware
var route = layer.route;
......@@ -185,8 +190,8 @@ proto.handle = function(req, res, done) {
// if final route, then we support options
if (route) {
// we don't run any routes with error first
if (err) {
return next(err);
if (layerError) {
return next(layerError);
}
var method = req.method;
......@@ -210,36 +215,33 @@ proto.handle = function(req, res, done) {
req.params = self.mergeParams
? mergeParams(layer.params, parentParams)
: layer.params;
layerPath = layer.path;
var layerPath = layer.path;
// this should be done for the layer
return self.process_params(layer, paramcalled, req, res, function(err) {
self.process_params(layer, paramcalled, req, res, function (err) {
if (err) {
return next(err);
return next(layerError || err);
}
if (route) {
return layer.handle(req, res, next);
return layer.handle_request(req, res, next);
}
trim_prefix();
trim_prefix(layer, layerError, layerPath, path);
});
});
}
} catch (err) {
next(err);
}
function trim_prefix() {
var c = path[layerPath.length];
if (c && '/' != c && '.' != c) return next(err);
function trim_prefix(layer, layerError, layerPath, path) {
var c = path[layerPath.length];
if (c && '/' !== c && '.' !== c) return next(layerError);
// Trim off the part of the url that matches the route
// middleware (.use stuff) needs to have the path stripped
// Trim off the part of the url that matches the route
// middleware (.use stuff) needs to have the path stripped
if (layerPath.length !== 0) {
debug('trim prefix (%s) from url %s', layerPath, req.url);
removed = layerPath;
if (removed.length) {
debug('trim prefix (%s) from url %s', layerPath, req.url);
req.url = protohost + req.url.substr(protohost.length + removed.length);
}
req.url = protohost + req.url.substr(protohost.length + removed.length);
// Ensure leading slash
if (!fqdn && req.url[0] !== '/') {
......@@ -248,27 +250,42 @@ proto.handle = function(req, res, done) {
}
// Setup base URL (no trailing slash)
if (removed.length && removed.substr(-1) === '/') {
req.baseUrl = parentUrl + removed.substring(0, removed.length - 1);
} else {
req.baseUrl = parentUrl + removed;
}
req.baseUrl = parentUrl + (removed[removed.length - 1] === '/'
? removed.substring(0, removed.length - 1)
: removed);
}
debug('%s %s : %s', layer.handle.name || 'anonymous', layerPath, req.originalUrl);
var arity = layer.handle.length;
try {
if (err && arity === 4) {
layer.handle(err, req, res, next);
} else if (!err && arity < 4) {
layer.handle(req, res, next);
} else {
next(err);
}
} catch (err) {
next(err);
}
debug('%s %s : %s', layer.name, layerPath, req.originalUrl);
if (layerError) {
layer.handle_error(layerError, req, res, next);
} else {
layer.handle_request(req, res, next);
}
}
};
/**
* Match request to a layer.
*
* @api private
*/
proto.match_layer = function match_layer(layer, req, res, done) {
var error = null;
var path;
try {
path = parseUrl(req).pathname;
if (!layer.match(path)) {
path = undefined;
}
} catch (err) {
error = err;
}
done(error, path);
};
/**
......@@ -338,11 +355,7 @@ proto.process_params = function(layer, called, req, res, done) {
value: paramVal
};
try {
return paramCallback();
} catch (err) {
return done(err);
}
paramCallback();
}
// single param callbacks
......@@ -361,7 +374,11 @@ proto.process_params = function(layer, called, req, res, done) {
if (!fn) return param();
fn(req, res, paramCallback, paramVal, key.name);
try {
fn(req, res, paramCallback, paramVal, key.name);
} catch (e) {
paramCallback(e);
}
}
param();
......@@ -379,40 +396,47 @@ proto.process_params = function(layer, called, req, res, done) {
* handlers can operate without any code changes regardless of the "prefix"
* pathname.
*
* @param {String|Function} route
* @param {Function} fn
* @return {app} for chaining
* @api public
*/
proto.use = function(route, fn){
// default route to '/'
if ('string' != typeof route) {
fn = route;
route = '/';
}
proto.use = function use(fn) {
var offset = 0;
var path = '/';
var self = this;
// default path to '/'
if (typeof fn !== 'function') {
var type = {}.toString.call(fn);
var msg = 'Router.use() requires callback functions but got a ' + type;
throw new Error(msg);
offset = 1;
path = fn;
}
// strip trailing slash
if ('/' == route[route.length - 1]) {
route = route.slice(0, -1);
var callbacks = utils.flatten(slice.call(arguments, offset));
if (callbacks.length === 0) {
throw new TypeError('Router.use() requires callback function');
}
var layer = new Layer(route, {
sensitive: this.caseSensitive,
strict: this.strict,
end: false
}, fn);
callbacks.forEach(function (fn) {
if (typeof fn !== 'function') {
var type = toString.call(fn);
var msg = 'Router.use() requires callback function but got a ' + type;
throw new TypeError(msg);
}
// add the middleware
debug('use %s %s', route || '/', fn.name || 'anonymous');
// add the middleware
debug('use %s %s', path, fn.name || '<anonymous>');
var layer = new Layer(path, {
sensitive: self.caseSensitive,
strict: false,
end: false
}, fn);
layer.route = undefined;
self.stack.push(layer);
});
this.stack.push(layer);
return this;
};
......@@ -448,7 +472,7 @@ proto.route = function(path){
methods.concat('all').forEach(function(method){
proto[method] = function(path){
var route = this.route(path)
route[method].apply(route, [].slice.call(arguments, 1));
route[method].apply(route, slice.call(arguments, 1));
return this;
};
});
......@@ -511,8 +535,14 @@ function restore(fn, obj) {
// wrap a function
function wrap(old, fn) {
return function () {
var args = [old].concat(slice.call(arguments));
return function proxy() {
var args = new Array(arguments.length + 1);
args[0] = old;
for (var i = 0, len = arguments.length; i < len; i++) {
args[i + 1] = arguments[i];
}
fn.apply(this, args);
};
}
......@@ -18,10 +18,67 @@ function Layer(path, options, fn) {
debug('new %s', path);
options = options || {};
this.regexp = pathRegexp(path, this.keys = [], options);
this.handle = fn;
this.name = fn.name || '<anonymous>';
this.params = undefined;
this.path = undefined;
this.regexp = pathRegexp(path, this.keys = [], options);
if (path === '/' && options.end === false) {
this.regexp.fast_slash = true;
}
}
/**
* Handle the error for the layer.
*
* @param {Error} error
* @param {Request} req
* @param {Response} res
* @param {function} next
* @api private
*/
Layer.prototype.handle_error = function handle_error(error, req, res, next) {
var fn = this.handle;
if (fn.length !== 4) {
// not a standard error handler
return next(error);
}
try {
fn(error, req, res, next);
} catch (err) {
next(err);
}
};
/**
* Handle the request for the layer.
*
* @param {Request} req
* @param {Response} res
* @param {function} next
* @api private
*/
Layer.prototype.handle_request = function handle(req, res, next) {
var fn = this.handle;
if (fn.length > 3) {
// not a standard request handler
return next();
}
try {
fn(req, res, next);
} catch (err) {
next(err);
}
};
/**
* Check if this route matches `path`, if so
* populate `.params`.
......@@ -31,18 +88,32 @@ function Layer(path, options, fn) {
* @api private
*/
Layer.prototype.match = function(path){
var keys = this.keys;
var params = this.params = {};
Layer.prototype.match = function match(path) {
if (this.regexp.fast_slash) {
// fast path non-ending match for / (everything matches)
this.params = {};
this.path = '';
return true;
}
var m = this.regexp.exec(path);
var n = 0;
var key;
var val;
if (!m) return false;
if (!m) {
this.params = undefined;
this.path = undefined;
return false;
}
// store values
this.params = {};
this.path = m[0];
var keys = this.keys;
var params = this.params;
var n = 0;
var key;
var val;
for (var i = 1, len = m.length; i < len; ++i) {
key = keys[i - 1];
val = decode_param(m[i]);
......
/**
* Module dependencies.
*/
var pathRegexp = require('path-to-regexp');
/**
* Expose `Layer`.
*/
module.exports = Match;
function Match(layer, path, params) {
this.layer = layer;
this.params = {};
this.path = path || '';
if (!params) {
return this;
}
var keys = layer.keys;
var n = 0;
var prop;
var key;
var val;
for (var i = 0; i < params.length; i++) {
key = keys[i];
val = decode_param(params[i]);
prop = key
? key.name
: n++;
this.params[prop] = val;
}
return this;
};
/**
* Decode param value.
*
* @param {string} val
* @return {string}
* @api private
*/
function decode_param(val){
if (typeof val !== 'string') {
return val;
}
try {
return decodeURIComponent(val);
} catch (e) {
var err = new TypeError("Failed to decode param '" + val + "'");
err.status = 400;
throw err;
}
}
......@@ -3,6 +3,7 @@
*/
var debug = require('debug')('express:router:route');
var Layer = require('./layer');
var methods = require('methods');
var utils = require('../utils');
......@@ -64,6 +65,7 @@ Route.prototype._options = function(){
*/
Route.prototype.dispatch = function(req, res, done){
var idx = 0;
var stack = this.stack;
if (stack.length === 0) {
return done();
......@@ -76,8 +78,9 @@ Route.prototype.dispatch = function(req, res, done){
req.route = this;
var idx = 0;
(function next_layer(err) {
next();
function next(err) {
if (err && err === 'route') {
return done();
}
......@@ -88,33 +91,15 @@ Route.prototype.dispatch = function(req, res, done){
}
if (layer.method && layer.method !== method) {
return next_layer(err);
return next(err);
}
var arity = layer.handle.length;
if (err) {
if (arity < 4) {
return next_layer(err);
}
try {
layer.handle(err, req, res, next_layer);
} catch (err) {
next_layer(err);
}
return;
layer.handle_error(err, req, res, next);
} else {
layer.handle_request(req, res, next);
}
if (arity > 3) {
return next_layer();
}
try {
layer.handle(req, res, next_layer);
} catch (err) {
next_layer(err);
}
})();
}
};
/**
......@@ -155,8 +140,11 @@ Route.prototype.all = function(){
throw new Error(msg);
}
var layer = Layer('/', {}, fn);
layer.method = undefined;
self.methods._all = true;
self.stack.push({ handle: fn });
self.stack.push(layer);
});
return self;
......@@ -176,11 +164,11 @@ methods.forEach(function(method){
debug('%s %s', method, self.path);
if (!self.methods[method]) {
self.methods[method] = true;
}
var layer = Layer('/', {}, fn);
layer.method = method;
self.stack.push({ method: method, handle: fn });
self.methods[method] = true;
self.stack.push(layer);
});
return self;
};
......
......@@ -35,5 +35,5 @@
"url": "https://github.com/expressjs/accepts/issues"
},
"_id": "accepts@1.0.7",
"_from": "accepts@~1.0.7"
"_from": "accepts@~1.0.5"
}
1.0.3 / 2014-07-09
==================
* Add support for multiple wildcards in namespaces (#122, @seegno)
* browser: fix lint
1.0.2 / 2014-06-10
==================
......
......@@ -66,7 +66,7 @@ function formatArgs() {
+ (useColors ? '%c ' : ' ')
+ '+' + exports.humanize(this.diff);
if (!useColors) return args
if (!useColors) return args;
var c = 'color: ' + this.color;
args = [args[0], c, ''].concat(Array.prototype.slice.call(args, 1));
......
......@@ -2,7 +2,7 @@
"name": "debug",
"repo": "visionmedia/debug",
"description": "small debugging utility",
"version": "1.0.2",
"version": "1.0.3",
"keywords": [
"debug",
"log",
......
......@@ -141,7 +141,7 @@ function enable(namespaces) {
for (var i = 0; i < len; i++) {
if (!split[i]) continue; // ignore empty strings
namespaces = split[i].replace('*', '.*?');
namespaces = split[i].replace(/\*/g, '.*?');
if (namespaces[0] === '-') {
exports.skips.push(new RegExp('^' + namespaces.substr(1) + '$'));
} else {
......
{
"name": "debug",
"version": "1.0.2",
"version": "1.0.3",
"repository": {
"type": "git",
"url": "git://github.com/visionmedia/debug.git"
......@@ -42,6 +42,6 @@
"bugs": {
"url": "https://github.com/visionmedia/debug/issues"
},
"_id": "debug@1.0.2",
"_from": "debug@1.0.2"
"_id": "debug@1.0.3",
"_from": "debug@1.0.3"
}
0.0.3 / 2014-07-11
==================
* deps: debug@1.0.3
- Add support for multiple wildcards in namespaces
0.0.2 / 2014-06-19
==================
......
{
"name": "finalhandler",
"description": "Node.js final http responder",
"version": "0.0.2",
"version": "0.0.3",
"author": {
"name": "Douglas Christopher Wilson",
"email": "doug@somethingdoug.com"
......@@ -12,11 +12,11 @@
"url": "git://github.com/expressjs/finalhandler"
},
"dependencies": {
"debug": "1.0.2",
"debug": "1.0.3",
"escape-html": "1.0.1"
},
"devDependencies": {
"istanbul": "0.2.10",
"istanbul": "0.3.0",
"mocha": "~1.20.1",
"should": "~4.0.1",
"supertest": "~0.13.0"
......@@ -34,6 +34,6 @@
"bugs": {
"url": "https://github.com/expressjs/finalhandler/issues"
},
"_id": "finalhandler@0.0.2",
"_from": "finalhandler@0.0.2"
"_id": "finalhandler@0.0.3",
"_from": "finalhandler@0.0.3"
}
......@@ -29,5 +29,6 @@
"url": "https://github.com/visionmedia/node-fresh/issues"
},
"_id": "fresh@0.2.2",
"_from": "fresh@0.2.2"
"_from": "fresh@0.2.2",
"scripts": {}
}
1.1.0 / 2014-07-05
==================
* add CONNECT
1.0.1 / 2014-06-02
==================
......
......@@ -34,7 +34,8 @@ if (http.METHODS) {
'subscribe',
'unsubscribe',
'patch',
'search'
'search',
'connect'
];
}
{
"name": "methods",
"version": "1.0.1",
"version": "1.1.0",
"description": "HTTP methods that node supports",
"main": "index.js",
"scripts": {
......@@ -26,6 +26,6 @@
"bugs": {
"url": "https://github.com/visionmedia/node-methods/issues"
},
"_id": "methods@1.0.1",
"_from": "methods@1.0.1"
"_id": "methods@1.1.0",
"_from": "methods@1.1.0"
}
1.1.3 / 2014-07-08
==================
* Fix typo
1.1.2 / 2014-07-08
==================
* Seriously fix Node.js 0.8 compatibility
1.1.1 / 2014-07-08
==================
* Fix Node.js 0.8 compatibility
1.1.0 / 2014-07-08
==================
* Incorporate URL href-only parse fast-path
1.0.1 / 2014-03-08
==================
* Add missing `require`
1.0.0 / 2014-03-08
==================
* Genesis from `connect`
......@@ -4,9 +4,9 @@ Parse a URL with memoization.
## API
### var pathname = parseurl(req)
### var parsedUrl = parseurl(req)
`pathname` can then be passed to a router or something.
`parsedUrl` is basically a `url.parse()` object.
## LICENSE
......@@ -31,4 +31,4 @@ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
var parse = require('url').parse;
/**
* Module dependencies.
*/
var url = require('url')
var parse = url.parse
var Url = url.Url
/**
* Pattern for a simple path case.
* See: https://github.com/joyent/node/pull/7878
*/
var simplePathRegExp = /^(\/\/?(?!\/)[^\?\s]*)(\?[^\s]*)?$/
var tryFastRegExp = /^\/[^\\#]*$/
/**
* Parse the `req` url with memoization.
*
* @param {ServerRequest} req
* @return {Object}
* @api private
* @api public
*/
module.exports = function parseUrl(req){
var parsed = req._parsedUrl;
if (parsed && parsed.href == req.url) {
return parsed;
} else {
parsed = parse(req.url);
if (parsed.auth && !parsed.protocol && ~parsed.href.indexOf('//')) {
// This parses pathnames, and a strange pathname like //r@e should work
parsed = parse(req.url.replace(/@/g, '%40'));
}
var parsed = req._parsedUrl
return req._parsedUrl = parsed;
if (fresh(req, parsed)) {
return parsed
}
parsed = fastparse(req.url)
if (parsed.auth && !parsed.protocol && parsed.href.indexOf('//') !== -1) {
// This parses pathnames, and a strange pathname like //r@e should work
parsed = fastparse(req.url.replace(/@/g, '%40'))
}
return req._parsedUrl = parsed
};
/**
* Parse the `str` url with fast-path short-cut.
*
* @param {string} str
* @return {Object}
* @api private
*/
function fastparse(str) {
if (typeof str === 'string' && tryFastRegExp.test(str)) {
// Try fast path regexp
// See: https://github.com/joyent/node/pull/7878
var simplePath = simplePathRegExp.exec(str)
// Construct simple URL
if (simplePath) {
var url = Url !== undefined
? new Url()
: {}
url.path = str
url.href = str
url.pathname = simplePath[1]
if (simplePath[2]) {
url.search = simplePath[2];
url.query = url.search.substr(1);
}
return url
}
}
return parse(str)
}
/**
* Determine if parsed is still fresh for req.
*
* @param {ServerRequest} req
* @param {object} parsedUrl
* @return {boolean}
* @api private
*/
function fresh(req, parsedUrl) {
return typeof parsedUrl === 'object'
&& parsedUrl !== null
&& (Url === undefined || parsedUrl instanceof Url)
&& parsedUrl.href === req.url
}
{
"name": "parseurl",
"description": "parse a url with memoization",
"version": "1.0.1",
"version": "1.1.3",
"author": {
"name": "Jonathan Ong",
"email": "me@jongleberry.com",
......@@ -16,8 +16,8 @@
"email": "me@jongleberry.com"
},
"license": "MIT",
"readme": "# parseurl\n\nParse a URL with memoization.\n\n## API\n\n### var pathname = parseurl(req)\n\n`pathname` can then be passed to a router or something.\n\n## LICENSE\n\n(The MIT License)\n\nCopyright (c) 2014 Jonathan Ong <me@jongleberry.com>\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n'Software'), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.",
"readme": "# parseurl\n\nParse a URL with memoization.\n\n## API\n\n### var parsedUrl = parseurl(req)\n\n`parsedUrl` is basically a `url.parse()` object.\n\n## LICENSE\n\n(The MIT License)\n\nCopyright (c) 2014 Jonathan Ong <me@jongleberry.com>\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n'Software'), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n",
"readmeFilename": "README.md",
"_id": "parseurl@1.0.1",
"_from": "parseurl@1.0.1"
"_id": "parseurl@1.1.3",
"_from": "parseurl@~1.1.3"
}
0.1.3 / 2014-07-06
==================
* Better array support
* Improved support for trailing slash in non-ending mode
0.1.0 / 2014-03-06
==================
......
{
"name": "path-to-regexp",
"description": "Express style path to RegExp utility",
"version": "0.1.0",
"version": "0.1.3",
"keywords": [
"express",
"regexp",
......
......@@ -22,22 +22,33 @@ module.exports = pathtoRegexp;
function pathtoRegexp(path, keys, options) {
options = options || {};
var sensitive = options.sensitive;
var strict = options.strict;
var end = options.end !== false;
var flags = options.sensitive ? '' : 'i';
keys = keys || [];
if (path instanceof RegExp) return path;
if (path instanceof Array) path = '(' + path.join('|') + ')';
if (path instanceof RegExp) {
return path;
}
path = path
.concat(strict ? '' : '/?')
if (Array.isArray(path)) {
// Map array parts into regexps and return their source. We also pass
// the same keys and options instance into every generation to get
// consistent matching groups before we join the sources together.
path = path.map(function (value) {
return pathtoRegexp(value, keys, options).source;
});
return new RegExp('(?:' + path.join('|') + ')', flags);
}
path = ('^' + path + (strict ? '' : path[path.length - 1] === '/' ? '?' : '/?'))
.replace(/\/\(/g, '/(?:')
.replace(/([\/\.])/g, '\\$1')
.replace(/(\\\/)?(\\\.)?:(\w+)(\(.*?\))?(\*)?(\?)?/g, function (match, slash, format, key, capture, star, optional) {
slash = slash || '';
format = format || '';
capture = capture || '([^/' + format + ']+?)';
capture = capture || '([^\\/' + format + ']+?)';
optional = optional || '';
keys.push({ name: key, optional: !!optional });
......@@ -52,5 +63,8 @@ function pathtoRegexp(path, keys, options) {
})
.replace(/\*/g, '(.*)');
return new RegExp('^' + path + (end ? '$' : '(?=\/|$)'), sensitive ? '' : 'i');
// If the path is non-ending, match until the end or a slash.
path += (end ? '$' : (path[path.length - 1] === '/' ? '' : '(?=\\/|$)'));
return new RegExp(path, flags);
};
{
"name": "path-to-regexp",
"description": "Express style path to RegExp utility",
"version": "0.1.2",
"version": "0.1.3",
"scripts": {
"test": "istanbul cover _mocha -- -R spec"
},
......@@ -27,6 +27,6 @@
"bugs": {
"url": "https://github.com/component/path-to-regexp/issues"
},
"_id": "path-to-regexp@0.1.2",
"_from": "path-to-regexp@0.1.2"
"_id": "path-to-regexp@0.1.3",
"_from": "path-to-regexp@0.1.3"
}
......@@ -46,6 +46,30 @@ describe('path-to-regexp', function () {
assert.ok(!m);
});
it('should do strict matches with trailing slashes', function () {
var params = [];
var re = pathToRegExp('/:test/', params, { strict: true });
var m;
assert.equal(params.length, 1);
assert.equal(params[0].name, 'test');
assert.equal(params[0].optional, false);
m = re.exec('/route');
assert.ok(!m);
m = re.exec('/route/');
assert.equal(m.length, 2);
assert.equal(m[0], '/route/');
assert.equal(m[1], 'route');
m = re.exec('/route//');
assert.ok(!m);
});
it('should allow optional express format params', function () {
var params = [];
var re = pathToRegExp('/:test?', params);
......@@ -388,19 +412,75 @@ describe('path-to-regexp', function () {
assert.equal(m[1], 'test');
});
it('should match trailing slashes in non-ending non-strict mode', function () {
var params = [];
var re = pathToRegExp('/route/', params, { end: false });
var m;
assert.equal(params.length, 0);
m = re.exec('/route/');
assert.equal(m.length, 1);
assert.equal(m[0], '/route/');
m = re.exec('/route/test');
assert.equal(m.length, 1);
assert.equal(m[0], '/route');
m = re.exec('/route');
assert.equal(m.length, 1);
assert.equal(m[0], '/route');
m = re.exec('/route//');
assert.equal(m.length, 1);
assert.equal(m[0], '/route/');
});
it('should match trailing slashing in non-ending strict mode', function () {
var params = [];
var re = pathToRegExp('/route/', params, { end: false, strict: true });
assert.equal(params.length, 0);
m = re.exec('/route/');
assert.equal(m.length, 1);
assert.equal(m[0], '/route/');
m = re.exec('/route/test');
assert.equal(m.length, 1);
assert.equal(m[0], '/route/');
m = re.exec('/route');
assert.ok(!m);
m = re.exec('/route//');
assert.equal(m.length, 1);
assert.equal(m[0], '/route/');
});
it('should not match trailing slashes in non-ending strict mode', function () {
var params = [];
var re = pathToRegExp('/:test', params, { end: false, strict: true });
var re = pathToRegExp('/route', params, { end: false, strict: true });
assert.equal(params.length, 1);
assert.equal(params[0].name, 'test');
assert.equal(params[0].optional, false);
assert.equal(params.length, 0);
m = re.exec('/test/');
m = re.exec('/route');
assert.equal(m.length, 2);
assert.equal(m[0], '/test');
assert.equal(m[1], 'test');
assert.equal(m.length, 1);
assert.equal(m[0], '/route');
m = re.exec('/route/');
assert.ok(m.length, 1);
assert.equal(m[0], '/route');
});
it('should match text after an express param', function () {
......@@ -502,9 +582,35 @@ describe('path-to-regexp', function () {
it('should join arrays parts', function () {
var re = pathToRegExp(['/test', '/route']);
assert.ok(re.exec('/test'));
assert.ok(re.exec('/route'));
assert.ok(!re.exec('/else'));
assert.ok(re.test('/test'));
assert.ok(re.test('/route'));
assert.ok(!re.test('/else'));
});
it('should match parts properly', function () {
var params = [];
var re = pathToRegExp(['/:test', '/test/:route'], params);
var m;
assert.equal(params.length, 2);
assert.equal(params[0].name, 'test');
assert.equal(params[0].optional, false);
assert.equal(params[1].name, 'route');
assert.equal(params[1].optional, false);
m = re.exec('/route');
assert.equal(m.length, 3);
assert.equal(m[0], '/route');
assert.equal(m[1], 'route');
assert.equal(m[2], undefined);
m = re.exec('/test/path');
assert.equal(m.length, 3);
assert.equal(m[0], '/test/path');
assert.equal(m[1], undefined);
assert.equal(m[2], 'path');
});
});
});
......@@ -29,5 +29,6 @@
"url": "https://github.com/visionmedia/node-range-parser/issues"
},
"_id": "range-parser@1.0.0",
"_from": "range-parser@~1.0.0"
"_from": "range-parser@~1.0.0",
"scripts": {}
}
0.6.0 / 2014-07-11
==================
* Deprecate `from` option; use `root` option
* Deprecate `send.etag()` -- use `etag` in `options`
* Deprecate `send.hidden()` -- use `hidden` in `options`
* Deprecate `send.index()` -- use `index` in `options`
* Deprecate `send.maxage()` -- use `maxAge` in `options`
* Deprecate `send.root()` -- use `root` in `options`
* deps: debug@1.0.3
- Add support for multiple wildcards in namespaces
0.5.0 / 2014-06-28
==================
......
......@@ -79,7 +79,7 @@ var app = http.createServer(function(req, res){
set `false` or to supply a new index pass a string or an array
in preferred order.
#### maxage
#### maxAge
Provide a max-age in milliseconds for http caching, defaults to 0.
This can also be a string accepted by the
......@@ -98,30 +98,6 @@ var app = http.createServer(function(req, res){
- `stream` file streaming has started `(stream)`
- `end` streaming has completed
### .etag(bool)
Enable or disable etag generation, defaults to true.
### .root(dir)
Serve files relative to `path`. Aliased as `.from(dir)`.
### .index(paths)
By default send supports "index.html" files, to disable this
invoke `.index(false)` or to supply a new index pass a string
or an array in preferred order.
### .maxage(ms)
Provide a max-age in milliseconds for http caching, defaults to 0.
This can also be a string accepted by the
[ms](https://www.npmjs.org/package/ms#readme) module.
### .hidden(bool)
Enable or disable transfer of hidden files, defaults to false.
## Error-handling
By default when no `error` listeners are present an automatic response will be made, otherwise you have full control over the response, aka you may show a 5xx page etc.
......
......@@ -4,6 +4,7 @@
*/
var debug = require('debug')('send')
var deprecate = require('depd')('send')
var escapeHtml = require('escape-html')
, parseRange = require('range-parser')
, Stream = require('stream')
......@@ -20,6 +21,10 @@ var escapeHtml = require('escape-html')
var EventEmitter = require('events').EventEmitter;
var ms = require('ms');
/**
* Variables.
*/
var maxMaxAge = 60 * 60 * 24 * 365 * 1000; // 1 year
var upPathRegexp = /(?:^|[\\\/])\.\.(?:[\\\/]|$)/;
/**
......@@ -78,11 +83,32 @@ function SendStream(req, path, options) {
this.req = req;
this.path = path;
this.options = options;
this.etag(('etag' in options) ? options.etag : true);
this.maxage(options.maxage);
this.hidden(options.hidden);
this.index(('index' in options) ? options.index : 'index.html');
if (options.root || options.from) this.root(options.root || options.from);
this._etag = options.etag !== undefined
? Boolean(options.etag)
: true
this._hidden = Boolean(options.hidden)
this._index = options.index !== undefined
? normalizeIndex(options.index)
: ['index.html']
this._maxage = options.maxAge || options.maxage
this._maxage = typeof this._maxage === 'string'
? ms(this._maxage)
: Number(this._maxage)
this._maxage = !isNaN(this._maxage)
? Math.min(Math.max(0, this._maxage), maxMaxAge)
: 0
this._root = options.root
? normalize(options.root)
: null
if (!this._root && options.from) {
this.from(options.from);
}
}
/**
......@@ -99,12 +125,12 @@ SendStream.prototype.__proto__ = Stream.prototype;
* @api public
*/
SendStream.prototype.etag = function(val){
SendStream.prototype.etag = deprecate.function(function etag(val) {
val = Boolean(val);
debug('etag %s', val);
this._etag = val;
return this;
};
}, 'send.etag: pass etag as option');
/**
* Enable or disable "hidden" (dot) files.
......@@ -114,12 +140,12 @@ SendStream.prototype.etag = function(val){
* @api public
*/
SendStream.prototype.hidden = function(val){
SendStream.prototype.hidden = deprecate.function(function hidden(val) {
val = Boolean(val);
debug('hidden %s', val);
this._hidden = val;
return this;
};
}, 'send.hidden: pass hidden as option');
/**
* Set index `paths`, set to a falsy
......@@ -130,12 +156,12 @@ SendStream.prototype.hidden = function(val){
* @api public
*/
SendStream.prototype.index = function index(paths){
var index = !paths ? [] : Array.isArray(paths) ? paths : [paths];
SendStream.prototype.index = deprecate.function(function index(paths) {
var index = !paths ? [] : normalizeIndex(paths);
debug('index %o', paths);
this._index = index;
return this;
};
}, 'send.index: pass index as option');
/**
* Set root `path`.
......@@ -145,13 +171,18 @@ SendStream.prototype.index = function index(paths){
* @api public
*/
SendStream.prototype.root =
SendStream.prototype.from = function(path){
SendStream.prototype.root = function(path){
path = String(path);
this._root = normalize(path);
return this;
};
SendStream.prototype.from = deprecate.function(SendStream.prototype.root,
'send.from: pass root as option');
SendStream.prototype.root = deprecate.function(SendStream.prototype.root,
'send.root: pass root as option');
/**
* Set max-age to `maxAge`.
*
......@@ -160,7 +191,7 @@ SendStream.prototype.from = function(path){
* @api public
*/
SendStream.prototype.maxage = function maxage(maxAge){
SendStream.prototype.maxage = deprecate.function(function maxage(maxAge) {
maxAge = typeof maxAge === 'string'
? ms(maxAge)
: Number(maxAge);
......@@ -169,7 +200,7 @@ SendStream.prototype.maxage = function maxage(maxAge){
debug('max-age %d', maxAge);
this._maxage = maxAge;
return this;
};
}, 'send.maxage: pass maxAge as option');
/**
* Emit error with `status`.
......@@ -431,6 +462,8 @@ SendStream.prototype.send = function(path, stat){
return this.headersAlreadySent();
}
debug('options %o', options);
// set header fields
this.setHeader(path, stat);
......@@ -622,3 +655,14 @@ SendStream.prototype.setHeader = function setHeader(path, stat){
res.setHeader('ETag', etag);
}
};
/**
* Normalize the index option into an array.
*
* @param {boolean|string|array} val
* @api private
*/
function normalizeIndex(val){
return [].concat(val || [])
}
......@@ -31,5 +31,6 @@
"url": "https://github.com/broofa/node-mime/issues"
},
"_id": "mime@1.2.11",
"_from": "mime@1.2.11"
"_from": "mime@1.2.11",
"scripts": {}
}
1.3.2 / 2014-07-11
==================
* deps: send@0.6.0
- deps: debug@1.0.3
1.3.1 / 2014-07-09
==================
* deps: parseurl@~1.1.3
- faster parsing of href-only URLs
1.3.0 / 2014-06-28
==================
* Add `setHeaders` option
* Include HTML link in redirect response
* deps: send@0.5.0
- Accept string for `maxAge` (converted by `ms`)
1.2.3 / 2014-06-11
==================
* deps: send@0.4.3
- Do not throw un-catchable error on file open race condition
- Use `escape-html` for HTML escaping
- deps: debug@1.0.2
- deps: finished@1.2.2
- deps: fresh@0.2.2
1.2.2 / 2014-06-09
==================
* deps: send@0.4.2
- fix "event emitter leak" warnings
- deps: debug@1.0.1
- deps: finished@1.2.1
1.2.1 / 2014-06-02
==================
* use `escape-html` for escaping
* deps: send@0.4.1
- Send `max-age` in `Cache-Control` in correct format
1.2.0 / 2014-05-29
==================
* deps: send@0.4.0
- Calculate ETag with md5 for reduced collisions
- Fix wrong behavior when index file matches directory
- Ignore stream errors after request ends
- Skip directories in index file search
- deps: debug@0.8.1
1.1.0 / 2014-04-24
==================
* Accept options directly to `send` module
* deps: send@0.3.0
1.0.4 / 2014-04-07
==================
* Resolve relative paths at middleware setup
* Use parseurl to parse the URL from request
1.0.3 / 2014-03-20
==================
* Do not rely on connect-like environments
1.0.2 / 2014-03-06
==================
* deps: send@0.2.0
1.0.1 / 2014-03-05
==================
* Add mime export for back-compat
1.0.0 / 2014-03-05
==================
* Genesis from `connect`
(The MIT License)
Copyright (c) 2010 Sencha Inc.
Copyright (c) 2011 LearnBoost
Copyright (c) 2011 TJ Holowaychuk
Copyright (c) 2014 Douglas Christopher Wilson
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# serve-static
[![NPM version](https://badge.fury.io/js/serve-static.svg)](http://badge.fury.io/js/serve-static)
[![Build Status](https://travis-ci.org/expressjs/serve-static.svg?branch=master)](https://travis-ci.org/expressjs/serve-static)
[![Coverage Status](https://img.shields.io/coveralls/expressjs/serve-static.svg?branch=master)](https://coveralls.io/r/expressjs/serve-static)
Previously `connect.static()`.
## Install
```sh
$ npm install serve-static
```
## API
```js
var serveStatic = require('serve-static')
```
### serveStatic(root, options)
Create a new middleware function to serve files from within a given root
directory. The file to serve will be determined by combining `req.url`
with the provided root directory.
Options:
- `hidden` Allow transfer of hidden files. defaults to `false`
- `index` Default file name, defaults to `'index.html'`
- `maxAge` Browser cache maxAge in milliseconds. This can also be a string accepted by the [ms](https://www.npmjs.org/package/ms#readme) module. defaults to `0`
- `redirect` Redirect to trailing "/" when the pathname is a dir. defaults to `true`
- `setHeaders` Function to set custom headers on response.
## Examples
### Serve files with vanilla node.js http server
```js
var finalhandler = require('finalhandler')
var http = require('http')
var serveStatic = require('serve-static')
// Serve up public/ftp folder
var serve = serveStatic('public/ftp', {'index': ['index.html', 'index.htm']})
// Create server
var server = http.createServer(function(req, res){
var done = finalhandler(req, res)
serve(req, res, done)
})
// Listen
server.listen(3000)
```
### Serve all files from ftp folder
```js
var connect = require('connect')
var serveStatic = require('serve-static')
var app = connect()
app.use(serveStatic('public/ftp', {'index': ['default.html', 'default.htm']}))
app.listen(3000)
```
### Serve all files as downloads
```js
var express = require('express')
var serveStatic = require('serve-static')
var app = express()
app.use(serveStatic('public/ftp', {
'index': false,
'setHeaders': setHeaders
}))
app.listen(3000)
function setHeaders(res, path) {
res.attachment(path)
}
```
## License
The MIT License (MIT)
Copyright (c) 2014 Douglas Christopher Wilson
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
/*!
* serve-static
* Copyright(c) 2010 Sencha Inc.
* Copyright(c) 2011 TJ Holowaychuk
* Copyright(c) 2014 Douglas Christopher Wilson
* MIT Licensed
*/
/**
* Module dependencies.
*/
var escapeHtml = require('escape-html');
var parseurl = require('parseurl');
var resolve = require('path').resolve;
var send = require('send');
var url = require('url');
/**
* @param {String} root
* @param {Object} options
* @return {Function}
* @api public
*/
exports = module.exports = function(root, options){
options = extend({}, options);
// root required
if (!root) throw new TypeError('root path required');
// resolve root to absolute
root = resolve(root);
// default redirect
var redirect = false !== options.redirect;
// headers listener
var setHeaders = options.setHeaders
delete options.setHeaders
if (setHeaders && typeof setHeaders !== 'function') {
throw new TypeError('option setHeaders must be function')
}
// setup options for send
options.maxage = options.maxage || options.maxAge || 0;
options.root = root;
return function staticMiddleware(req, res, next) {
if ('GET' != req.method && 'HEAD' != req.method) return next();
var opts = extend({}, options);
var originalUrl = url.parse(req.originalUrl || req.url);
var path = parseurl(req).pathname;
if (path === '/' && originalUrl.pathname[originalUrl.pathname.length - 1] !== '/') {
// make sure redirect occurs at mount
path = ''
}
// create send stream
var stream = send(req, path, opts)
if (redirect) {
// redirect relative to originalUrl
stream.on('directory', function redirect() {
originalUrl.pathname += '/'
var target = url.format(originalUrl)
res.statusCode = 303
res.setHeader('Content-Type', 'text/html; charset=utf-8')
res.setHeader('Location', target)
res.end('Redirecting to <a href="' + escapeHtml(target) + '">' + escapeHtml(target) + '</a>\n')
})
} else {
// forward to next middleware on directory
stream.on('directory', next)
}
// add headers listener
if (setHeaders) {
stream.on('headers', setHeaders)
}
// forward non-404 errors
stream.on('error', function error(err) {
next(err.status === 404 ? null : err)
})
// pipe
stream.pipe(res)
};
};
/**
* Expose mime module.
*
* If you wish to extend the mime table use this
* reference to the "mime" module in the npm registry.
*/
exports.mime = send.mime;
/**
* Shallow clone a single object.
*
* @param {Object} obj
* @param {Object} source
* @return {Object}
* @api private
*/
function extend(obj, source) {
if (!source) return obj;
for (var prop in source) {
obj[prop] = source[prop];
}
return obj;
};
{
"name": "serve-static",
"description": "Serve static files",
"version": "1.3.2",
"author": {
"name": "Douglas Christopher Wilson",
"email": "doug@somethingdoug.com"
},
"license": "MIT",
"repository": {
"type": "git",
"url": "git://github.com/expressjs/serve-static"
},
"dependencies": {
"escape-html": "1.0.1",
"parseurl": "~1.1.3",
"send": "0.6.0"
},
"devDependencies": {
"istanbul": "0.3.0",
"mocha": "~1.20.0",
"should": "~4.0.0",
"supertest": "~0.13.0"
},
"engines": {
"node": ">= 0.8.0"
},
"scripts": {
"test": "mocha --reporter dot --require should test/",
"test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --reporter dot --require should test/",
"test-travis": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --reporter spec --require should test/"
},
"readme": "# serve-static\n\n[![NPM version](https://badge.fury.io/js/serve-static.svg)](http://badge.fury.io/js/serve-static)\n[![Build Status](https://travis-ci.org/expressjs/serve-static.svg?branch=master)](https://travis-ci.org/expressjs/serve-static)\n[![Coverage Status](https://img.shields.io/coveralls/expressjs/serve-static.svg?branch=master)](https://coveralls.io/r/expressjs/serve-static)\n\nPreviously `connect.static()`.\n\n## Install\n\n```sh\n$ npm install serve-static\n```\n\n## API\n\n```js\nvar serveStatic = require('serve-static')\n```\n\n### serveStatic(root, options)\n\nCreate a new middleware function to serve files from within a given root\ndirectory. The file to serve will be determined by combining `req.url`\nwith the provided root directory.\n\nOptions:\n\n- `hidden` Allow transfer of hidden files. defaults to `false`\n- `index` Default file name, defaults to `'index.html'`\n- `maxAge` Browser cache maxAge in milliseconds. This can also be a string accepted by the [ms](https://www.npmjs.org/package/ms#readme) module. defaults to `0`\n- `redirect` Redirect to trailing \"/\" when the pathname is a dir. defaults to `true`\n- `setHeaders` Function to set custom headers on response.\n\n## Examples\n\n### Serve files with vanilla node.js http server\n\n```js\nvar finalhandler = require('finalhandler')\nvar http = require('http')\nvar serveStatic = require('serve-static')\n\n// Serve up public/ftp folder\nvar serve = serveStatic('public/ftp', {'index': ['index.html', 'index.htm']})\n\n// Create server\nvar server = http.createServer(function(req, res){\n var done = finalhandler(req, res)\n serve(req, res, done)\n})\n\n// Listen\nserver.listen(3000)\n```\n\n### Serve all files from ftp folder\n\n```js\nvar connect = require('connect')\nvar serveStatic = require('serve-static')\n\nvar app = connect()\n\napp.use(serveStatic('public/ftp', {'index': ['default.html', 'default.htm']}))\napp.listen(3000)\n```\n\n### Serve all files as downloads\n\n```js\nvar express = require('express')\nvar serveStatic = require('serve-static')\n\nvar app = express()\n\napp.use(serveStatic('public/ftp', {\n 'index': false,\n 'setHeaders': setHeaders\n}))\napp.listen(3000)\n\nfunction setHeaders(res, path) {\n res.attachment(path)\n}\n```\n\n## License\n\nThe MIT License (MIT)\n\nCopyright (c) 2014 Douglas Christopher Wilson\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n",
"readmeFilename": "Readme.md",
"bugs": {
"url": "https://github.com/expressjs/serve-static/issues"
},
"_id": "serve-static@1.3.2",
"_from": "serve-static@~1.3.2"
}
{
"name": "express",
"description": "Fast, unopinionated, minimalist web framework",
"version": "4.5.1",
"version": "4.6.1",
"author": {
"name": "TJ Holowaychuk",
"email": "tj@vision-media.ca"
......@@ -50,30 +50,30 @@
"dependencies": {
"accepts": "~1.0.7",
"buffer-crc32": "0.2.3",
"debug": "1.0.2",
"debug": "1.0.3",
"depd": "0.3.0",
"escape-html": "1.0.1",
"finalhandler": "0.0.2",
"finalhandler": "0.0.3",
"media-typer": "0.2.0",
"methods": "1.0.1",
"parseurl": "1.0.1",
"methods": "1.1.0",
"parseurl": "~1.1.3",
"path-to-regexp": "0.1.3",
"proxy-addr": "1.0.1",
"range-parser": "1.0.0",
"send": "0.5.0",
"serve-static": "~1.3.0",
"send": "0.6.0",
"serve-static": "~1.3.2",
"type-is": "~1.3.2",
"vary": "0.1.0",
"cookie": "0.1.2",
"fresh": "0.2.2",
"cookie-signature": "1.0.4",
"merge-descriptors": "0.0.2",
"utils-merge": "1.0.0",
"qs": "0.6.6",
"path-to-regexp": "0.1.2"
"utils-merge": "1.0.0"
},
"devDependencies": {
"after": "0.8.1",
"istanbul": "0.2.14",
"istanbul": "0.3.0",
"mocha": "~1.20.1",
"should": "~4.0.4",
"supertest": "~0.13.0",
......@@ -84,8 +84,8 @@
"hjs": "~0.0.6",
"body-parser": "~1.4.3",
"cookie-parser": "~1.3.1",
"express-session": "~1.6.1",
"method-override": "2.0.2",
"express-session": "~1.6.5",
"method-override": "~2.1.1",
"multiparty": "~3.3.0",
"morgan": "1.1.1",
"vhost": "2.0.0"
......@@ -99,11 +99,11 @@
"test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --require test/support/env --reporter dot --check-leaks test/ test/acceptance/",
"test-travis": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --require test/support/env --reporter spec --check-leaks test/ test/acceptance/"
},
"readme": "[![Express Logo](https://i.cloudup.com/zfY6lL7eFa-3000x3000.png)](https://expressjs.com/)\n\n Fast, unopinionated, minimalist web framework for [node](https://nodejs.org).\n\n [![NPM Version](https://badge.fury.io/js/express.svg)](https://badge.fury.io/js/express)\n [![Build Status](https://travis-ci.org/visionmedia/express.svg?branch=master)](https://travis-ci.org/visionmedia/express)\n [![Coverage Status](https://img.shields.io/coveralls/visionmedia/express.svg)](https://coveralls.io/r/visionmedia/express)\n [![Gittip](https://img.shields.io/gittip/visionmedia.svg)](https://www.gittip.com/visionmedia/)\n\n```js\nvar express = require('express')\nvar app = express()\n\napp.get('/', function (req, res) {\n res.send('Hello World')\n})\n\napp.listen(3000)\n```\n\n **PROTIP** Be sure to read [Migrating from 3.x to 4.x](https://github.com/visionmedia/express/wiki/Migrating-from-3.x-to-4.x) as well as [New features in 4.x](https://github.com/visionmedia/express/wiki/New-features-in-4.x).\n\n### Installation\n\n```bash\n$ npm install express\n```\n\n## Quick Start\n\n The quickest way to get started with express is to utilize the executable [`express(1)`](https://github.com/expressjs/generator) to generate an application as shown below:\n\n Install the executable. The executable's major version will match Express's:\n\n```bash\n$ npm install -g express-generator@4\n```\n\n Create the app:\n\n```bash\n$ express /tmp/foo && cd /tmp/foo\n```\n\n Install dependencies:\n\n```bash\n$ npm install\n```\n\n Start the server:\n\n```bash\n$ npm start\n```\n\n## Features\n\n * Robust routing\n * HTTP helpers (redirection, caching, etc)\n * View system supporting 14+ template engines\n * Content negotiation\n * Focus on high performance\n * Executable for generating applications quickly\n * High test coverage\n\n## Philosophy\n\n The Express philosophy is to provide small, robust tooling for HTTP servers, making\n it a great solution for single page applications, web sites, hybrids, or public\n HTTP APIs.\n\n Express does not force you to use any specific ORM or template engine. With support for over\n 14 template engines via [Consolidate.js](https://github.com/visionmedia/consolidate.js),\n you can quickly craft your perfect framework.\n\n## More Information\n\n * [Website and Documentation](http://expressjs.com/) - [[website repo](https://github.com/visionmedia/expressjs.com)]\n * [Github Organization](https://github.com/expressjs) for Official Middleware & Modules\n * [#express](https://webchat.freenode.net/?channels=express) on freenode IRC\n * Visit the [Wiki](https://github.com/visionmedia/express/wiki)\n * [Google Group](https://groups.google.com/group/express-js) for discussion\n * [Русскоязычная документация](http://jsman.ru/express/)\n * Run express examples [online](https://runnable.com/express)\n\n## Viewing Examples\n\n Clone the Express repo, then install the dev dependencies to install all the example / test suite dependencies:\n\n```bash\n$ git clone git://github.com/visionmedia/express.git --depth 1\n$ cd express\n$ npm install\n```\n\n Then run whichever example you want:\n\n $ node examples/content-negotiation\n\n You can also view live examples here:\n\n <a href=\"https://runnable.com/express\" target=\"_blank\"><img src=\"https://runnable.com/external/styles/assets/runnablebtn.png\" style=\"width:67px;height:25px;\"></a>\n\n## Running Tests\n\n To run the test suite, first invoke the following command within the repo, installing the development dependencies:\n\n```bash\n$ npm install\n```\n\n Then run the tests:\n\n```bash\n$ npm test\n```\n\n### Contributors\n\n * Author: [TJ Holowaychuk](https://github.com/visionmedia)\n * Lead Maintainer: [Douglas Christopher Wilson](https://github.com/dougwilson)\n * [All Contributors](https://github.com/visionmedia/express/graphs/contributors)\n\n### License\n\n [MIT](LICENSE)\n",
"readme": "[![Express Logo](https://i.cloudup.com/zfY6lL7eFa-3000x3000.png)](https://expressjs.com/)\n\n Fast, unopinionated, minimalist web framework for [node](http://nodejs.org).\n\n [![NPM Version](https://badge.fury.io/js/express.svg)](https://badge.fury.io/js/express)\n [![Build Status](https://travis-ci.org/visionmedia/express.svg?branch=master)](https://travis-ci.org/visionmedia/express)\n [![Coverage Status](https://img.shields.io/coveralls/visionmedia/express.svg)](https://coveralls.io/r/visionmedia/express)\n [![Gittip](https://img.shields.io/gittip/visionmedia.svg)](https://www.gittip.com/visionmedia/)\n\n```js\nvar express = require('express')\nvar app = express()\n\napp.get('/', function (req, res) {\n res.send('Hello World')\n})\n\napp.listen(3000)\n```\n\n **PROTIP** Be sure to read [Migrating from 3.x to 4.x](https://github.com/visionmedia/express/wiki/Migrating-from-3.x-to-4.x) as well as [New features in 4.x](https://github.com/visionmedia/express/wiki/New-features-in-4.x).\n\n### Installation\n\n```bash\n$ npm install express\n```\n\n## Quick Start\n\n The quickest way to get started with express is to utilize the executable [`express(1)`](https://github.com/expressjs/generator) to generate an application as shown below:\n\n Install the executable. The executable's major version will match Express's:\n\n```bash\n$ npm install -g express-generator@4\n```\n\n Create the app:\n\n```bash\n$ express /tmp/foo && cd /tmp/foo\n```\n\n Install dependencies:\n\n```bash\n$ npm install\n```\n\n Start the server:\n\n```bash\n$ npm start\n```\n\n## Features\n\n * Robust routing\n * HTTP helpers (redirection, caching, etc)\n * View system supporting 14+ template engines\n * Content negotiation\n * Focus on high performance\n * Executable for generating applications quickly\n * High test coverage\n\n## Philosophy\n\n The Express philosophy is to provide small, robust tooling for HTTP servers, making\n it a great solution for single page applications, web sites, hybrids, or public\n HTTP APIs.\n\n Express does not force you to use any specific ORM or template engine. With support for over\n 14 template engines via [Consolidate.js](https://github.com/visionmedia/consolidate.js),\n you can quickly craft your perfect framework.\n\n## More Information\n\n * [Website and Documentation](http://expressjs.com/) - [[website repo](https://github.com/visionmedia/expressjs.com)]\n * [Github Organization](https://github.com/expressjs) for Official Middleware & Modules\n * [#express](https://webchat.freenode.net/?channels=express) on freenode IRC\n * Visit the [Wiki](https://github.com/visionmedia/express/wiki)\n * [Google Group](https://groups.google.com/group/express-js) for discussion\n * [Русскоязычная документация](http://jsman.ru/express/)\n * Run express examples [online](https://runnable.com/express)\n\n## Viewing Examples\n\n Clone the Express repo, then install the dev dependencies to install all the example / test suite dependencies:\n\n```bash\n$ git clone git://github.com/visionmedia/express.git --depth 1\n$ cd express\n$ npm install\n```\n\n Then run whichever example you want:\n\n $ node examples/content-negotiation\n\n You can also view live examples here:\n\n <a href=\"https://runnable.com/express\" target=\"_blank\"><img src=\"https://runnable.com/external/styles/assets/runnablebtn.png\" style=\"width:67px;height:25px;\"></a>\n\n## Running Tests\n\n To run the test suite, first invoke the following command within the repo, installing the development dependencies:\n\n```bash\n$ npm install\n```\n\n Then run the tests:\n\n```bash\n$ npm test\n```\n\n### Contributors\n\n * Author: [TJ Holowaychuk](https://github.com/visionmedia)\n * Lead Maintainer: [Douglas Christopher Wilson](https://github.com/dougwilson)\n * [All Contributors](https://github.com/visionmedia/express/graphs/contributors)\n\n### License\n\n [MIT](LICENSE)\n",
"readmeFilename": "Readme.md",
"bugs": {
"url": "https://github.com/visionmedia/express/issues"
},
"_id": "express@4.5.1",
"_id": "express@4.6.1",
"_from": "express@4.x"
}
test
\ No newline at end of file
language: node_js
node_js:
- "0.11"
- "0.10"
- "0.9"
- "0.8"
- "0.6"
- "0.4"
before_install:
- '[ "${TRAVIS_NODE_VERSION}" == "0.6" ] || npm install -g npm@~1.4.6'
matrix:
fast_finish: true
allow_failures:
- node_js: "0.11"
- node_js: "0.9"
- node_js: "0.6"
- node_js: "0.4"
The MIT License (MIT)
Copyright (c) 2014 Stefan Thomas
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
[![Build Status][1]][2] [![dependency status][9]][10] [![dev dependency status][11]][12]
# extend() for Node.js <sup>[![Version Badge][8]][3]</sup>
`node-extend` is a port of the classic extend() method from jQuery. It behaves as you expect. It is simple, tried and true.
## Installation
This package is available on [npm][3] as: `extend`
``` sh
npm install extend
```
## Usage
**Syntax:** extend **(** [`deep`], `target`, `object1`, [`objectN`] **)**
*Extend one object with one or more others, returning the modified object.*
Keep in mind that the target object will be modified, and will be returned from extend().
If a boolean true is specified as the first argument, extend performs a deep copy, recursively copying any objects it finds. Otherwise, the copy will share structure with the original object(s).
Undefined properties are not copied. However, properties inherited from the object's prototype will be copied over.
Warning: passing `false` as the first argument is not supported.
### Arguments
* `deep` *Boolean* (optional)
If set, the merge becomes recursive (i.e. deep copy).
* `target` *Object*
The object to extend.
* `object1` *Object*
The object that will be merged into the first.
* `objectN` *Object* (Optional)
More objects to merge into the first.
## License
`node-extend` is licensed under the [MIT License][4].
## Acknowledgements
All credit to the jQuery authors for perfecting this amazing utility.
Ported to Node.js by [Stefan Thomas][5] with contributions by [Jonathan Buchanan][6] and [Jordan Harband][7].
[1]: https://travis-ci.org/justmoon/node-extend.svg
[2]: https://travis-ci.org/justmoon/node-extend
[3]: https://npmjs.org/package/extend
[4]: http://opensource.org/licenses/MIT
[5]: https://github.com/justmoon
[6]: https://github.com/insin
[7]: https://github.com/ljharb
[8]: http://vb.teelaun.ch/justmoon/node-extend.svg
[9]: https://david-dm.org/justmoon/node-extend.svg
[10]: https://david-dm.org/justmoon/node-extend
[11]: https://david-dm.org/justmoon/node-extend/dev-status.svg
[12]: https://david-dm.org/justmoon/node-extend#info=devDependencies
{
"name": "extend",
"author": "Stefan Thomas <justmoon@members.fsf.org> (http://www.justmoon.net)",
"version": "1.3.0",
"description": "Port of jQuery.extend for node.js and the browser.",
"scripts": [
"index.js"
],
"contributors": [
{
"name": "Jordan Harband",
"url": "https://github.com/ljharb"
}
],
"keywords": [
"extend",
"clone",
"merge"
],
"repository" : {
"type": "git",
"url": "https://github.com/justmoon/node-extend.git"
},
"dependencies": {
},
"devDependencies": {
"tape" : "~2.12.3",
"covert": "~0.4.0"
}
}
var hasOwn = Object.prototype.hasOwnProperty;
var toString = Object.prototype.toString;
var undefined;
var isPlainObject = function isPlainObject(obj) {
"use strict";
if (!obj || toString.call(obj) !== '[object Object]' || obj.nodeType || obj.setInterval) {
return false;
}
var has_own_constructor = hasOwn.call(obj, 'constructor');
var has_is_property_of_method = obj.constructor && obj.constructor.prototype && hasOwn.call(obj.constructor.prototype, 'isPrototypeOf');
// Not own constructor property must be Object
if (obj.constructor && !has_own_constructor && !has_is_property_of_method) {
return false;
}
// Own properties are enumerated firstly, so to speed up,
// if last one is own, then all properties are own.
var key;
for (key in obj) {}
return key === undefined || hasOwn.call(obj, key);
};
module.exports = function extend() {
"use strict";
var options, name, src, copy, copyIsArray, clone,
target = arguments[0],
i = 1,
length = arguments.length,
deep = false;
// Handle a deep copy situation
if (typeof target === "boolean") {
deep = target;
target = arguments[1] || {};
// skip the boolean and the target
i = 2;
} else if (typeof target !== "object" && typeof target !== "function" || target == undefined) {
target = {};
}
for (; i < length; ++i) {
// Only deal with non-null/undefined values
if ((options = arguments[i]) != null) {
// Extend the base object
for (name in options) {
src = target[name];
copy = options[name];
// Prevent never-ending loop
if (target === copy) {
continue;
}
// Recurse if we're merging plain objects or arrays
if (deep && copy && (isPlainObject(copy) || (copyIsArray = Array.isArray(copy)))) {
if (copyIsArray) {
copyIsArray = false;
clone = src && Array.isArray(src) ? src : [];
} else {
clone = src && isPlainObject(src) ? src : {};
}
// Never move original objects, clone them
target[name] = extend(deep, clone, copy);
// Don't bring in undefined values
} else if (copy !== undefined) {
target[name] = copy;
}
}
}
}
// Return the modified object
return target;
};
{
"name": "extend",
"author": {
"name": "Stefan Thomas",
"email": "justmoon@members.fsf.org",
"url": "http://www.justmoon.net"
},
"version": "1.3.0",
"description": "Port of jQuery.extend for node.js and the browser",
"main": "index",
"scripts": {
"test": "node test/index.js",
"coverage": "covert test/index.js",
"coverage-quiet": "covert test/index.js --quiet"
},
"contributors": [
{
"name": "Jordan Harband",
"url": "https://github.com/ljharb"
}
],
"keywords": [
"extend",
"clone",
"merge"
],
"repository": {
"type": "git",
"url": "https://github.com/justmoon/node-extend.git"
},
"dependencies": {},
"devDependencies": {
"tape": "~2.13.2",
"covert": "~0.4.0"
},
"readme": "[![Build Status][1]][2] [![dependency status][9]][10] [![dev dependency status][11]][12]\n\n# extend() for Node.js <sup>[![Version Badge][8]][3]</sup>\n\n`node-extend` is a port of the classic extend() method from jQuery. It behaves as you expect. It is simple, tried and true.\n\n## Installation\n\nThis package is available on [npm][3] as: `extend`\n\n``` sh\nnpm install extend\n```\n\n## Usage\n\n**Syntax:** extend **(** [`deep`], `target`, `object1`, [`objectN`] **)**\n\n*Extend one object with one or more others, returning the modified object.*\n\nKeep in mind that the target object will be modified, and will be returned from extend().\n\nIf a boolean true is specified as the first argument, extend performs a deep copy, recursively copying any objects it finds. Otherwise, the copy will share structure with the original object(s).\nUndefined properties are not copied. However, properties inherited from the object's prototype will be copied over.\nWarning: passing `false` as the first argument is not supported.\n\n### Arguments\n\n* `deep` *Boolean* (optional)\nIf set, the merge becomes recursive (i.e. deep copy).\n* `target`\t*Object*\nThe object to extend.\n* `object1`\t*Object*\nThe object that will be merged into the first.\n* `objectN` *Object* (Optional)\nMore objects to merge into the first.\n\n## License\n\n`node-extend` is licensed under the [MIT License][4].\n\n## Acknowledgements\n\nAll credit to the jQuery authors for perfecting this amazing utility.\n\nPorted to Node.js by [Stefan Thomas][5] with contributions by [Jonathan Buchanan][6] and [Jordan Harband][7].\n\n[1]: https://travis-ci.org/justmoon/node-extend.svg\n[2]: https://travis-ci.org/justmoon/node-extend\n[3]: https://npmjs.org/package/extend\n[4]: http://opensource.org/licenses/MIT\n[5]: https://github.com/justmoon\n[6]: https://github.com/insin\n[7]: https://github.com/ljharb\n[8]: http://vb.teelaun.ch/justmoon/node-extend.svg\n[9]: https://david-dm.org/justmoon/node-extend.svg\n[10]: https://david-dm.org/justmoon/node-extend\n[11]: https://david-dm.org/justmoon/node-extend/dev-status.svg\n[12]: https://david-dm.org/justmoon/node-extend#info=devDependencies\n\n",
"readmeFilename": "README.md",
"bugs": {
"url": "https://github.com/justmoon/node-extend/issues"
},
"_id": "extend@1.3.0",
"_from": "extend@*"
}
1.4.0 / 2014-07-21
==================
* deps: parseurl@~1.2.0
- Cache URLs based on original value
- Remove no-longer-needed URL mis-parse work-around
- Simplify the "fast-path" `RegExp`
* deps: send@0.7.0
- Add `dotfiles` option
- deps: debug@1.0.4
- deps: depd@0.4.2
1.3.2 / 2014-07-11
==================
* deps: send@0.6.0
- Cap `maxAge` value to 1 year
- deps: debug@1.0.3
1.3.1 / 2014-07-09
==================
......
......@@ -4,8 +4,6 @@
[![Build Status](https://travis-ci.org/expressjs/serve-static.svg?branch=master)](https://travis-ci.org/expressjs/serve-static)
[![Coverage Status](https://img.shields.io/coveralls/expressjs/serve-static.svg?branch=master)](https://coveralls.io/r/expressjs/serve-static)
Previously `connect.static()`.
## Install
```sh
......@@ -22,15 +20,50 @@ var serveStatic = require('serve-static')
Create a new middleware function to serve files from within a given root
directory. The file to serve will be determined by combining `req.url`
with the provided root directory.
with the provided root directory. When a file is not found, instead of
sending a 404 response, this module will instead call `next()` to move on
to the next middleware, allowing for stacking and fall-backs.
#### Options
##### dotfiles
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 call `next()`.
##### etag
Enable or disable etag generation, defaults to true.
##### index
By default this module will send "index.html" files in response to a request
on a directory. To disable this set `false` or to supply a new index pass a
string or an array in preferred order.
##### maxAge
Provide a max-age in milliseconds for http caching, defaults to 0. This
can also be a string accepted by the [ms](https://www.npmjs.org/package/ms#readme)
module.
##### redirect
Redirect to trailing "/" when the pathname is a dir. Defaults to `true`.
Options:
##### setHeaders
- `hidden` Allow transfer of hidden files. defaults to `false`
- `index` Default file name, defaults to `'index.html'`
- `maxAge` Browser cache maxAge in milliseconds. This can also be a string accepted by the [ms](https://www.npmjs.org/package/ms#readme) module. defaults to `0`
- `redirect` Redirect to trailing "/" when the pathname is a dir. defaults to `true`
- `setHeaders` Function to set custom headers on response.
Function to set custom headers on response.
## Examples
......
# Compiled source #
###################
*.com
*.class
*.dll
*.exe
*.o
*.so
# Packages #
############
# it's better to unpack these files and commit the raw source
# git has its own built in compression methods
*.7z
*.dmg
*.gz
*.iso
*.jar
*.rar
*.tar
*.zip
# Logs and databases #
######################
*.log
*.sql
*.sqlite
# OS generated files #
######################
.DS_Store*
# Icon?
ehthumbs.db
Thumbs.db
# Node.js #
###########
lib-cov
*.seed
*.log
*.csv
*.dat
*.out
*.pid
*.gz
pids
logs
results
node_modules
npm-debug.log
# Components #
##############
/build
/components
/public
\ No newline at end of file
benchmark/
coverage/
test/
.travis.yml
1.2.0 / 2014-07-21
==================
* Cache URLs based on original value
* Remove no-longer-needed URL mis-parse work-around
* Simplify the "fast-path" `RegExp`
1.1.3 / 2014-07-08
==================
......
(The MIT License)
Copyright (c) 2014 Jonathan Ong <me@jongleberry.com>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# parseurl
[![NPM version](https://badge.fury.io/js/parseurl.svg)](http://badge.fury.io/js/parseurl)
[![Build Status](https://travis-ci.org/expressjs/parseurl.svg?branch=master)](https://travis-ci.org/expressjs/parseurl)
[![Coverage Status](https://img.shields.io/coveralls/expressjs/parseurl.svg?branch=master)](https://coveralls.io/r/expressjs/parseurl)
Parse a URL with memoization.
## Install
```bash
$ npm install parseurl
```
## API
### var parsedUrl = parseurl(req)
```js
var parseurl = require('parseurl')
```
### parseurl(req)
Parse the URL of the given request object (looks at the `req.url` property)
and return the result. The result is the same as `url.parse` in Node.js core.
Calling this function multiple times on the same `req` where `req.url` does
not change will return a cached parsed object, rather than parsing again.
## Benchmark
```bash
$ npm run-script bench
> parseurl@1.2.0 bench nodejs-parseurl
> node benchmark/index.js
> node benchmark/fullurl.js
Parsing URL "http://localhost:8888/foo/bar?user=tj&pet=fluffy"
1 test completed.
2 tests completed.
3 tests completed.
fasturl x 1,290,780 ops/sec ±0.46% (195 runs sampled)
nativeurl x 56,401 ops/sec ±0.22% (196 runs sampled)
parseurl x 55,231 ops/sec ±0.22% (194 runs sampled)
> node benchmark/pathquery.js
Parsing URL "/foo/bar?user=tj&pet=fluffy"
1 test completed.
2 tests completed.
3 tests completed.
fasturl x 1,986,668 ops/sec ±0.27% (190 runs sampled)
nativeurl x 98,740 ops/sec ±0.21% (195 runs sampled)
parseurl x 2,628,171 ops/sec ±0.36% (195 runs sampled)
> node benchmark/samerequest.js
Parsing URL "/foo/bar?user=tj&pet=fluffy" on same request object
1 test completed.
2 tests completed.
3 tests completed.
fasturl x 2,184,468 ops/sec ±0.40% (194 runs sampled)
nativeurl x 99,437 ops/sec ±0.71% (194 runs sampled)
parseurl x 10,498,005 ops/sec ±0.61% (186 runs sampled)
> node benchmark/simplepath.js
Parsing URL "/foo/bar"
1 test completed.
2 tests completed.
3 tests completed.
`parsedUrl` is basically a `url.parse()` object.
fasturl x 4,535,825 ops/sec ±0.27% (191 runs sampled)
nativeurl x 98,769 ops/sec ±0.54% (191 runs sampled)
parseurl x 4,164,865 ops/sec ±0.34% (192 runs sampled)
## LICENSE
> node benchmark/slash.js
(The MIT License)
Parsing URL "/"
Copyright (c) 2014 Jonathan Ong <me@jongleberry.com>
1 test completed.
2 tests completed.
3 tests completed.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
fasturl x 4,908,405 ops/sec ±0.42% (191 runs sampled)
nativeurl x 100,945 ops/sec ±0.59% (188 runs sampled)
parseurl x 4,333,208 ops/sec ±0.27% (194 runs sampled)
```
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
## License
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
[MIT](LICENSE)
......@@ -12,8 +12,7 @@ var Url = url.Url
* See: https://github.com/joyent/node/pull/7878
*/
var simplePathRegExp = /^(\/\/?(?!\/)[^\?\s]*)(\?[^\s]*)?$/
var tryFastRegExp = /^\/[^\\#]*$/
var simplePathRegExp = /^(\/\/?(?!\/)[^\?#\s]*)(\?[^#\s]*)?$/
/**
* Parse the `req` url with memoization.
......@@ -25,17 +24,16 @@ var tryFastRegExp = /^\/[^\\#]*$/
module.exports = function parseUrl(req){
var parsed = req._parsedUrl
var url = req.url
if (fresh(req, parsed)) {
if (fresh(url, parsed)) {
// Return cached URL parse
return parsed
}
parsed = fastparse(req.url)
if (parsed.auth && !parsed.protocol && parsed.href.indexOf('//') !== -1) {
// This parses pathnames, and a strange pathname like //r@e should work
parsed = fastparse(req.url.replace(/@/g, '%40'))
}
// Parse the URL
parsed = fastparse(url)
parsed._raw = url
return req._parsedUrl = parsed
};
......@@ -49,44 +47,41 @@ module.exports = function parseUrl(req){
*/
function fastparse(str) {
if (typeof str === 'string' && tryFastRegExp.test(str)) {
// Try fast path regexp
// See: https://github.com/joyent/node/pull/7878
var simplePath = simplePathRegExp.exec(str)
// Construct simple URL
if (simplePath) {
var url = Url !== undefined
? new Url()
: {}
url.path = str
url.href = str
url.pathname = simplePath[1]
if (simplePath[2]) {
url.search = simplePath[2];
url.query = url.search.substr(1);
}
return url
}
// Try fast path regexp
// See: https://github.com/joyent/node/pull/7878
var simplePath = typeof str === 'string' && simplePathRegExp.exec(str)
// Construct simple URL
if (simplePath) {
var pathname = simplePath[1]
var search = simplePath[2] || null
var url = Url !== undefined
? new Url()
: {}
url.path = str
url.href = str
url.pathname = pathname
url.search = search
url.query = search && search.substr(1)
return url
}
return parse(str)
}
/**
* Determine if parsed is still fresh for req.
* Determine if parsed is still fresh for url.
*
* @param {ServerRequest} req
* @param {string} url
* @param {object} parsedUrl
* @return {boolean}
* @api private
*/
function fresh(req, parsedUrl) {
function fresh(url, parsedUrl) {
return typeof parsedUrl === 'object'
&& parsedUrl !== null
&& (Url === undefined || parsedUrl instanceof Url)
&& parsedUrl.href === req.url
&& parsedUrl._raw === url
}
{
"name": "parseurl",
"description": "parse a url with memoization",
"version": "1.1.3",
"version": "1.2.0",
"author": {
"name": "Jonathan Ong",
"email": "me@jongleberry.com",
"url": "http://jongleberry.com"
},
"contributors": [
{
"name": "Douglas Christopher Wilson",
"email": "doug@somethingdoug.com"
}
],
"repository": {
"type": "git",
"url": "https://github.com/expressjs/parseurl.git"
},
"bugs": {
"url": "https://github.com/expressjs/parseurl/issues",
"email": "me@jongleberry.com"
"url": "git://github.com/expressjs/parseurl"
},
"license": "MIT",
"readme": "# parseurl\n\nParse a URL with memoization.\n\n## API\n\n### var parsedUrl = parseurl(req)\n\n`parsedUrl` is basically a `url.parse()` object.\n\n## LICENSE\n\n(The MIT License)\n\nCopyright (c) 2014 Jonathan Ong <me@jongleberry.com>\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n'Software'), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n",
"devDependencies": {
"benchmark": "1.0.0",
"beautify-benchmark": "0.2.4",
"fast-url-parser": "~1.0.0",
"istanbul": "0.3.0",
"mocha": "~1.20.0"
},
"scripts": {
"bench": "node benchmark/index.js",
"test": "mocha --check-leaks --bail --reporter spec test/",
"test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --check-leaks --reporter dot test/",
"test-travis": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --check-leaks --reporter spec test/"
},
"readme": "# parseurl\n\n[![NPM version](https://badge.fury.io/js/parseurl.svg)](http://badge.fury.io/js/parseurl)\n[![Build Status](https://travis-ci.org/expressjs/parseurl.svg?branch=master)](https://travis-ci.org/expressjs/parseurl)\n[![Coverage Status](https://img.shields.io/coveralls/expressjs/parseurl.svg?branch=master)](https://coveralls.io/r/expressjs/parseurl)\n\nParse a URL with memoization.\n\n## Install\n\n```bash\n$ npm install parseurl\n```\n\n## API\n\n```js\nvar parseurl = require('parseurl')\n```\n\n### parseurl(req)\n\nParse the URL of the given request object (looks at the `req.url` property)\nand return the result. The result is the same as `url.parse` in Node.js core.\nCalling this function multiple times on the same `req` where `req.url` does\nnot change will return a cached parsed object, rather than parsing again.\n\n## Benchmark\n\n```bash\n$ npm run-script bench\n\n> parseurl@1.2.0 bench nodejs-parseurl\n> node benchmark/index.js\n\n> node benchmark/fullurl.js\n\n Parsing URL \"http://localhost:8888/foo/bar?user=tj&pet=fluffy\"\n\n 1 test completed.\n 2 tests completed.\n 3 tests completed.\n\n fasturl x 1,290,780 ops/sec ±0.46% (195 runs sampled)\n nativeurl x 56,401 ops/sec ±0.22% (196 runs sampled)\n parseurl x 55,231 ops/sec ±0.22% (194 runs sampled)\n\n> node benchmark/pathquery.js\n\n Parsing URL \"/foo/bar?user=tj&pet=fluffy\"\n\n 1 test completed.\n 2 tests completed.\n 3 tests completed.\n\n fasturl x 1,986,668 ops/sec ±0.27% (190 runs sampled)\n nativeurl x 98,740 ops/sec ±0.21% (195 runs sampled)\n parseurl x 2,628,171 ops/sec ±0.36% (195 runs sampled)\n\n> node benchmark/samerequest.js\n\n Parsing URL \"/foo/bar?user=tj&pet=fluffy\" on same request object\n\n 1 test completed.\n 2 tests completed.\n 3 tests completed.\n\n fasturl x 2,184,468 ops/sec ±0.40% (194 runs sampled)\n nativeurl x 99,437 ops/sec ±0.71% (194 runs sampled)\n parseurl x 10,498,005 ops/sec ±0.61% (186 runs sampled)\n\n> node benchmark/simplepath.js\n\n Parsing URL \"/foo/bar\"\n\n 1 test completed.\n 2 tests completed.\n 3 tests completed.\n\n fasturl x 4,535,825 ops/sec ±0.27% (191 runs sampled)\n nativeurl x 98,769 ops/sec ±0.54% (191 runs sampled)\n parseurl x 4,164,865 ops/sec ±0.34% (192 runs sampled)\n\n> node benchmark/slash.js\n\n Parsing URL \"/\"\n\n 1 test completed.\n 2 tests completed.\n 3 tests completed.\n\n fasturl x 4,908,405 ops/sec ±0.42% (191 runs sampled)\n nativeurl x 100,945 ops/sec ±0.59% (188 runs sampled)\n parseurl x 4,333,208 ops/sec ±0.27% (194 runs sampled)\n```\n\n## License\n\n [MIT](LICENSE)\n",
"readmeFilename": "README.md",
"_id": "parseurl@1.1.3",
"_from": "parseurl@~1.1.3"
"bugs": {
"url": "https://github.com/expressjs/parseurl/issues"
},
"_id": "parseurl@1.2.0",
"_from": "parseurl@~1.2.0"
}
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
==================
* Deprecate `from` option; use `root` option
* Deprecate `send.etag()` -- use `etag` in `options`
* Deprecate `send.hidden()` -- use `hidden` in `options`
* Deprecate `send.index()` -- use `index` in `options`
* Deprecate `send.maxage()` -- use `maxAge` in `options`
* Deprecate `send.root()` -- use `root` in `options`
* Cap `maxAge` value to 1 year
* deps: debug@1.0.3
- Add support for multiple wildcards in namespaces
0.5.0 / 2014-06-28
==================
......
......@@ -69,9 +69,20 @@ var app = http.createServer(function(req, res){
Enable or disable etag generation, defaults to true.
#### 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
......@@ -79,7 +90,7 @@ var app = http.createServer(function(req, res){
set `false` or to supply a new index pass a string or an array
in preferred order.
#### maxage
#### maxAge
Provide a max-age in milliseconds for http caching, defaults to 0.
This can also be a string accepted by the
......@@ -98,30 +109,6 @@ var app = http.createServer(function(req, res){
- `stream` file streaming has started `(stream)`
- `end` streaming has completed
### .etag(bool)
Enable or disable etag generation, defaults to true.
### .root(dir)
Serve files relative to `path`. Aliased as `.from(dir)`.
### .index(paths)
By default send supports "index.html" files, to disable this
invoke `.index(false)` or to supply a new index pass a string
or an array in preferred order.
### .maxage(ms)
Provide a max-age in milliseconds for http caching, defaults to 0.
This can also be a string accepted by the
[ms](https://www.npmjs.org/package/ms#readme) module.
### .hidden(bool)
Enable or disable transfer of hidden files, defaults to false.
## Error-handling
By default when no `error` listeners are present an automatic response will be made, otherwise you have full control over the response, aka you may show a 5xx page etc.
......
......@@ -4,6 +4,7 @@
*/
var debug = require('debug')('send')
var deprecate = require('depd')('send')
var escapeHtml = require('escape-html')
, parseRange = require('range-parser')
, Stream = require('stream')
......@@ -13,14 +14,19 @@ var escapeHtml = require('escape-html')
, http = require('http')
, onFinished = require('finished')
, fs = require('fs')
, basename = path.basename
, normalize = path.normalize
, join = path.join
, utils = require('./utils');
var EventEmitter = require('events').EventEmitter;
var ms = require('ms');
var upPathRegexp = /(?:^|[\\\/])\.\.(?:[\\\/]|$)/;
/**
* Variables.
*/
var maxMaxAge = 60 * 60 * 24 * 365 * 1000; // 1 year
var resolve = path.resolve
var sep = path.sep
var upPathRegexp = /(?:^|[\\\/])\.\.(?:[\\\/]|$)/
/**
* Expose `send`.
......@@ -59,13 +65,6 @@ function send(req, path, options) {
/**
* Initialize a `SendStream` with the given `path`.
*
* Events:
*
* - `error` an error occurred
* - `stream` file streaming has started
* - `end` streaming has completed
* - `directory` a directory was requested
*
* @param {Request} req
* @param {String} path
* @param {Object} options
......@@ -78,11 +77,49 @@ function SendStream(req, path, options) {
this.req = req;
this.path = path;
this.options = options;
this.etag(('etag' in options) ? options.etag : true);
this.maxage(options.maxage);
this.hidden(options.hidden);
this.index(('index' in options) ? options.index : 'index.html');
if (options.root || options.from) this.root(options.root || options.from);
this._etag = options.etag !== undefined
? Boolean(options.etag)
: true
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
? normalizeIndex(options.index)
: ['index.html']
this._maxage = options.maxAge || options.maxage
this._maxage = typeof this._maxage === 'string'
? ms(this._maxage)
: Number(this._maxage)
this._maxage = !isNaN(this._maxage)
? Math.min(Math.max(0, this._maxage), maxMaxAge)
: 0
this._root = options.root
? resolve(options.root)
: null
if (!this._root && options.from) {
this.from(options.from);
}
}
/**
......@@ -99,12 +136,12 @@ SendStream.prototype.__proto__ = Stream.prototype;
* @api public
*/
SendStream.prototype.etag = function(val){
SendStream.prototype.etag = deprecate.function(function etag(val) {
val = Boolean(val);
debug('etag %s', val);
this._etag = val;
return this;
};
}, 'send.etag: pass etag as option');
/**
* Enable or disable "hidden" (dot) files.
......@@ -114,12 +151,13 @@ SendStream.prototype.etag = function(val){
* @api public
*/
SendStream.prototype.hidden = function(val){
SendStream.prototype.hidden = deprecate.function(function hidden(val) {
val = Boolean(val);
debug('hidden %s', val);
this._hidden = val;
this._dotfiles = undefined
return this;
};
}, 'send.hidden: use dotfiles option');
/**
* Set index `paths`, set to a falsy
......@@ -130,12 +168,12 @@ SendStream.prototype.hidden = function(val){
* @api public
*/
SendStream.prototype.index = function index(paths){
var index = !paths ? [] : Array.isArray(paths) ? paths : [paths];
SendStream.prototype.index = deprecate.function(function index(paths) {
var index = !paths ? [] : normalizeIndex(paths);
debug('index %o', paths);
this._index = index;
return this;
};
}, 'send.index: pass index as option');
/**
* Set root `path`.
......@@ -145,13 +183,18 @@ SendStream.prototype.index = function index(paths){
* @api public
*/
SendStream.prototype.root =
SendStream.prototype.from = function(path){
SendStream.prototype.root = function(path){
path = String(path);
this._root = normalize(path);
this._root = resolve(path)
return this;
};
SendStream.prototype.from = deprecate.function(SendStream.prototype.root,
'send.from: pass root as option');
SendStream.prototype.root = deprecate.function(SendStream.prototype.root,
'send.root: pass root as option');
/**
* Set max-age to `maxAge`.
*
......@@ -160,7 +203,7 @@ SendStream.prototype.from = function(path){
* @api public
*/
SendStream.prototype.maxage = function maxage(maxAge){
SendStream.prototype.maxage = deprecate.function(function maxage(maxAge) {
maxAge = typeof maxAge === 'string'
? ms(maxAge)
: Number(maxAge);
......@@ -169,7 +212,7 @@ SendStream.prototype.maxage = function maxage(maxAge){
debug('max-age %d', maxAge);
this._maxage = maxAge;
return this;
};
}, 'send.maxage: pass maxAge as option');
/**
* Emit error with `status`.
......@@ -197,17 +240,6 @@ SendStream.prototype.error = function(status, err){
res.end(msg);
};
/**
* 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 "/".
*
......@@ -219,17 +251,6 @@ SendStream.prototype.hasTrailingSlash = function(){
return '/' == this.path[this.path.length - 1];
};
/**
* 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.
*
......@@ -369,30 +390,67 @@ SendStream.prototype.redirect = function(path){
SendStream.prototype.pipe = function(res){
var self = this
, args = arguments
, path = this.path
, root = this._root;
// references
this.res = res;
// 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)
// null byte(s)
if (~path.indexOf('\0')) return this.error(400);
// 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
if (this._index.length && this.hasTrailingSlash()) {
......@@ -431,6 +489,8 @@ SendStream.prototype.send = function(path, stat){
return this.headersAlreadySent();
}
debug('pipe "%s"', path)
// set header fields
this.setHeader(path, stat);
......@@ -622,3 +682,30 @@ SendStream.prototype.setHeader = function setHeader(path, stat){
res.setHeader('ETag', etag);
}
};
/**
* 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.
*
* @param {boolean|string|array} val
* @api private
*/
function normalizeIndex(val){
return [].concat(val || [])
}
1.0.4 / 2014-07-15
==================
* dist: recompile
* example: remove `console.info()` log usage
* example: add "Content-Type" UTF-8 header to browser example
* browser: place %c marker after the space character
* browser: reset the "content" color via `color: inherit`
* browser: add colors support for Firefox >= v31
* debug: prefer an instance `log()` function over the global one (#119)
* Readme: update documentation about styled console logs for FF v31 (#116, @wryk)
1.0.3 / 2014-07-09
==================
* Add support for multiple wildcards in namespaces (#122, @seegno)
* browser: fix lint
1.0.2 / 2014-06-10
==================
......
......@@ -91,7 +91,10 @@ setInterval(function(){
#### Web Inspector Colors
Colors are also enabled on "Web Inspectors" that understand the `%c` formatting
option. These are WebKit web inspectors, and the Firebug plugin for Firefox.
option. These are WebKit web inspectors, Firefox ([since version
31](https://hacks.mozilla.org/2014/05/editable-box-model-multiple-selection-sublime-text-keys-much-more-firefox-developer-tools-episode-31/))
and the Firebug plugin for Firefox (any version).
Colored output looks something like:
![](https://cloud.githubusercontent.com/assets/71256/3139768/b98c5fd8-e8ef-11e3-862a-f7253b6f47c6.png)
......
......@@ -26,9 +26,9 @@ exports.colors = [
];
/**
* Currently only WebKit-based Web Inspectors and the Firebug
* extension (*not* the built-in Firefox web inpector) are
* known to support "%c" CSS customizations.
* Currently only WebKit-based Web Inspectors, Firefox >= v31,
* and the Firebug extension (any Firefox version) are known
* to support "%c" CSS customizations.
*
* TODO: add a `localStorage` variable to explicitly enable/disable colors
*/
......@@ -37,7 +37,10 @@ function useColors() {
// is webkit? http://stackoverflow.com/a/16459606/376773
return ('WebkitAppearance' in document.documentElement.style) ||
// is firebug? http://stackoverflow.com/a/398120/376773
(window.console && (console.firebug || (console.exception && console.table)));
(window.console && (console.firebug || (console.exception && console.table))) ||
// is firefox >= v31?
// https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages
(navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/) && parseInt(RegExp.$1, 10) >= 31);
}
/**
......@@ -61,15 +64,15 @@ function formatArgs() {
args[0] = (useColors ? '%c' : '')
+ this.namespace
+ (useColors ? '%c ' : ' ')
+ (useColors ? ' %c' : ' ')
+ args[0]
+ (useColors ? '%c ' : ' ')
+ '+' + exports.humanize(this.diff);
if (!useColors) return args
if (!useColors) return args;
var c = 'color: ' + this.color;
args = [args[0], c, ''].concat(Array.prototype.slice.call(args, 1));
args = [args[0], c, 'color: inherit'].concat(Array.prototype.slice.call(args, 1));
// the final "%c" is somewhat tricky, because there could be other
// arguments passed either before or after the %c, so we need to
......
......@@ -2,7 +2,7 @@
"name": "debug",
"repo": "visionmedia/debug",
"description": "small debugging utility",
"version": "1.0.2",
"version": "1.0.4",
"keywords": [
"debug",
"log",
......
......@@ -113,7 +113,7 @@ function debug(namespace) {
if ('function' === typeof exports.formatArgs) {
args = exports.formatArgs.apply(self, args);
}
var logFn = exports.log || enabled.log || console.log.bind(console);
var logFn = enabled.log || exports.log || console.log.bind(console);
logFn.apply(self, args);
}
enabled.enabled = true;
......@@ -141,7 +141,7 @@ function enable(namespaces) {
for (var i = 0; i < len; i++) {
if (!split[i]) continue; // ignore empty strings
namespaces = split[i].replace('*', '.*?');
namespaces = split[i].replace(/\*/g, '.*?');
if (namespaces[0] === '-') {
exports.skips.push(new RegExp('^' + namespaces.substr(1) + '$'));
} else {
......
0.4.2 / 2014-07-19
==================
* Correct call site for wrapped functions and properties
0.4.1 / 2014-07-19
==================
* Improve automatic message generation for function properties
0.4.0 / 2014-07-19
==================
* Add `TRACE_DEPRECATION` environment variable
* Remove non-standard grey color from color output
* Support `--no-deprecation` argument
* Support `--trace-deprecation` argument
* Support `deprecate.property(fn, prop, message)`
0.3.0 / 2014-06-16
==================
* Add `NO_DEPRECATION` environment variable
0.2.0 / 2014-06-15
==================
* Add `deprecate.property(obj, prop, message)`
* Remove `supports-color` dependency for node.js 0.8
0.1.0 / 2014-06-15
==================
* Add `deprecate.function(fn, message)`
* Add `process.on('deprecation', fn)` emitter
* Automatically generate message when omitted from `deprecate()`
0.0.1 / 2014-06-15
==================
* Fix warning for dynamic calls at singe call site
0.0.0 / 2014-06-15
==================
* Initial implementation
(The MIT License)
Copyright (c) 2014 Douglas Christopher Wilson
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# depd
[![NPM version](https://badge.fury.io/js/depd.svg)](http://badge.fury.io/js/depd)
[![Build Status](https://travis-ci.org/dougwilson/nodejs-depd.svg?branch=master)](https://travis-ci.org/dougwilson/nodejs-depd)
[![Coverage Status](https://img.shields.io/coveralls/dougwilson/nodejs-depd.svg?branch=master)](https://coveralls.io/r/dougwilson/nodejs-depd)
Deprecate all the things
> With great modules comes great responsibility; mark things deprecated!
## Install
```sh
$ npm install depd
```
## API
```js
var deprecate = require('depd')('my-module')
```
This library allows you to display deprecation messages to your users.
This library goes above and beyond with deprecation warnings by
introspecting the call stack (but only the bits that it is interested
in).
Instead of just warning on the first invocation of a deprecated
function and never again, this module will warn on the first invocation
of a deprecated function per unique call site, making it ideal to alert
users of all deprecated uses across the code base, rather than just
whatever happens to execute first.
The deprecation warnings from this module also include the file and line
information for the call into the module that the deprecated function was
in.
### depd(namespace)
Create a new deprecate function that uses the given namespace name in the
messages and will display the call site prior to the stack entering the
file this function was called from. It is highly suggested you use the
name of your module as the namespace.
### deprecate(message)
Call this function from deprecated code to display a deprecation message.
This message will appear once per unique caller site. Caller site is the
first call site in the stack in a different file from the caller of this
function.
If the message is omitted, a message is generated for you based on the site
of the `deprecate()` call and will display the name of the function called,
similar to the name displayed in a stack trace.
### deprecate.function(fn, message)
Call this function to wrap a given function in a deprecation message on any
call to the function. An optional message can be supplied to provide a custom
message.
### deprecate.property(obj, prop, message)
Call this function to wrap a given property on object in a deprecation message
on any accessing or setting of the property. An optional message can be supplied
to provide a custom message.
The method must be called on the object where the property belongs (not
inherited from the prototype).
If the property is a data descriptor, it will be converted to an accessor
descriptor in order to display the deprecation message.
### process.on('deprecation', fn)
This module will allow easy capturing of deprecation errors by emitting the
errors as the type "deprecation" on the global `process`. If there are no
listeners for this type, the errors are written to STDERR as normal, but if
there are any listeners, nothing will be written to STDERR and instead only
emitted. From there, you can write the errors in a different format or to a
logging source.
The error represents the deprecation and is emitted only once with the same
rules as writing to STDERR. The error has the following properties:
- `message` - This is the message given by the library
- `name` - This is always `'DeprecationError'`
- `namespace` - This is the namespace the deprecation came from
- `stack` - This is the stack of the call to the deprecated thing
Example `error.stack` output:
```
DeprecationError: my-cool-module deprecated oldfunction
at Object.<anonymous> ([eval]-wrapper:6:22)
at Module._compile (module.js:456:26)
at evalScript (node.js:532:25)
at startup (node.js:80:7)
at node.js:902:3
```
### process.env.NO_DEPRECATION
As a user of modules that are deprecated, the environment variable `NO_DEPRECATION`
is provided as a quick solution to silencing deprecation warnings from being
output. The format of this is similar to that of `DEBUG`:
```sh
$ NO_DEPRECATION=my-module,othermod node app.js
```
This will suppress deprecations from being output for "my-module" and "othermod".
The value is a list of comma-separated namespaces. To suppress every warning
across all namespaces, use the value `*` for a namespace.
Providing the argument `--no-deprecation` to the `node` executable will suppress
all deprecations.
**NOTE** This will not suppress the deperecations given to any "deprecation"
event listeners, just the output to STDERR.
### process.env.TRACE_DEPRECATION
As a user of modules that are deprecated, the environment variable `TRACE_DEPRECATION`
is provided as a solution to getting more detailed location information in deprecation
warnings by including the entire stack trace. The format of this is the same as
`NO_DEPRECATION`:
```sh
$ TRACE_DEPRECATION=my-module,othermod node app.js
```
This will include stack traces for deprecations being output for "my-module" and
"othermod". The value is a list of comma-separated namespaces. To trace every
warning across all namespaces, use the value `*` for a namespace.
Providing the argument `--trace-deprecation` to the `node` executable will trace
all deprecations.
**NOTE** This will not trace the deperecations silenced by `NO_DEPRECATION`.
## Display
![message](files/message.png)
When a user calls a function in your library that you mark deprecated, they
will see the following written to STDERR (in the given colors, similar colors
and layout to the `debug` module):
```
bright cyan bright yellow
| | reset cyan
| | | |
▼ ▼ ▼ ▼
my-cool-module deprecated oldfunction [eval]-wrapper:6:22
▲ ▲ ▲ ▲
| | | |
namespace | | location of mycoolmod.oldfunction() call
| deprecation message
the word "deprecated"
```
If the user redirects their STDERR to a file or somewhere that does not support
colors, they see (similar layout to the `debug` module):
```
Sun, 15 Jun 2014 05:21:37 GMT my-cool-module deprecated oldfunction at [eval]-wrapper:6:22
▲ ▲ ▲ ▲ ▲
| | | | |
timestamp of message namespace | | location of mycoolmod.oldfunction() call
| deprecation message
the word "deprecated"
```
## Examples
### Deprecating all calls to a function
This will display a deprecated message about "oldfunction" being deprecated
from "my-module" on STDERR.
```js
var deprecate = require('depd')('my-cool-module')
// message automatically derived from function name
// Object.oldfunction
exports.oldfunction = deprecate.function(function oldfunction() {
// all calls to function are deprecated
})
// specific message
exports.oldfunction = deprecate.function(function () {
// all calls to function are deprecated
}, 'oldfunction')
```
### Conditionally deprecating a function call
This will display a deprecated message about "weirdfunction" being deprecated
from "my-module" on STDERR when called with less than 2 arguments.
```js
var deprecate = require('depd')('my-cool-module')
exports.weirdfunction = function () {
if (arguments.length < 2) {
// calls with 0 or 1 args are deprecated
deprecate('weirdfunction args < 2')
}
}
```
When calling `deprecate` as a function, the warning is counted per call site
within your own module, so you can display different deprecations depending
on different situations and the users will still get all the warnings:
```js
var deprecate = require('depd')('my-cool-module')
exports.weirdfunction = function () {
if (arguments.length < 2) {
// calls with 0 or 1 args are deprecated
deprecate('weirdfunction args < 2')
} else if (typeof arguments[0] !== 'string') {
// calls with non-string first argument are deprecated
deprecate('weirdfunction non-string first arg')
}
}
```
### Deprecating property access
This will display a deprecated message about "oldprop" being deprecated
from "my-module" on STDERR when accessed. A deprecation will be displayed
when setting the value and when getting the value.
```js
var deprecate = require('depd')('my-cool-module')
exports.oldprop = 'something'
// message automatically derives from property name
deprecate.property(exports, 'oldprop')
// explicit message
deprecate.property(exports, 'oldprop', 'oldprop >= 0.10')
```
## License
The MIT License (MIT)
Copyright (c) 2014 Douglas Christopher Wilson
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
{
"name": "serve-static",
"description": "Serve static files",
"version": "1.3.1",
"version": "1.4.0",
"author": {
"name": "Douglas Christopher Wilson",
"email": "doug@somethingdoug.com"
......@@ -13,8 +13,8 @@
},
"dependencies": {
"escape-html": "1.0.1",
"parseurl": "~1.1.3",
"send": "0.5.0"
"parseurl": "~1.2.0",
"send": "0.7.0"
},
"devDependencies": {
"istanbul": "0.3.0",
......@@ -30,11 +30,11 @@
"test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --reporter dot --require should test/",
"test-travis": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --reporter spec --require should test/"
},
"readme": "# serve-static\n\n[![NPM version](https://badge.fury.io/js/serve-static.svg)](http://badge.fury.io/js/serve-static)\n[![Build Status](https://travis-ci.org/expressjs/serve-static.svg?branch=master)](https://travis-ci.org/expressjs/serve-static)\n[![Coverage Status](https://img.shields.io/coveralls/expressjs/serve-static.svg?branch=master)](https://coveralls.io/r/expressjs/serve-static)\n\nPreviously `connect.static()`.\n\n## Install\n\n```sh\n$ npm install serve-static\n```\n\n## API\n\n```js\nvar serveStatic = require('serve-static')\n```\n\n### serveStatic(root, options)\n\nCreate a new middleware function to serve files from within a given root\ndirectory. The file to serve will be determined by combining `req.url`\nwith the provided root directory.\n\nOptions:\n\n- `hidden` Allow transfer of hidden files. defaults to `false`\n- `index` Default file name, defaults to `'index.html'`\n- `maxAge` Browser cache maxAge in milliseconds. This can also be a string accepted by the [ms](https://www.npmjs.org/package/ms#readme) module. defaults to `0`\n- `redirect` Redirect to trailing \"/\" when the pathname is a dir. defaults to `true`\n- `setHeaders` Function to set custom headers on response.\n\n## Examples\n\n### Serve files with vanilla node.js http server\n\n```js\nvar finalhandler = require('finalhandler')\nvar http = require('http')\nvar serveStatic = require('serve-static')\n\n// Serve up public/ftp folder\nvar serve = serveStatic('public/ftp', {'index': ['index.html', 'index.htm']})\n\n// Create server\nvar server = http.createServer(function(req, res){\n var done = finalhandler(req, res)\n serve(req, res, done)\n})\n\n// Listen\nserver.listen(3000)\n```\n\n### Serve all files from ftp folder\n\n```js\nvar connect = require('connect')\nvar serveStatic = require('serve-static')\n\nvar app = connect()\n\napp.use(serveStatic('public/ftp', {'index': ['default.html', 'default.htm']}))\napp.listen(3000)\n```\n\n### Serve all files as downloads\n\n```js\nvar express = require('express')\nvar serveStatic = require('serve-static')\n\nvar app = express()\n\napp.use(serveStatic('public/ftp', {\n 'index': false,\n 'setHeaders': setHeaders\n}))\napp.listen(3000)\n\nfunction setHeaders(res, path) {\n res.attachment(path)\n}\n```\n\n## License\n\nThe MIT License (MIT)\n\nCopyright (c) 2014 Douglas Christopher Wilson\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n",
"readme": "# serve-static\n\n[![NPM version](https://badge.fury.io/js/serve-static.svg)](http://badge.fury.io/js/serve-static)\n[![Build Status](https://travis-ci.org/expressjs/serve-static.svg?branch=master)](https://travis-ci.org/expressjs/serve-static)\n[![Coverage Status](https://img.shields.io/coveralls/expressjs/serve-static.svg?branch=master)](https://coveralls.io/r/expressjs/serve-static)\n\n## Install\n\n```sh\n$ npm install serve-static\n```\n\n## API\n\n```js\nvar serveStatic = require('serve-static')\n```\n\n### serveStatic(root, options)\n\nCreate a new middleware function to serve files from within a given root\ndirectory. The file to serve will be determined by combining `req.url`\nwith the provided root directory. When a file is not found, instead of\nsending a 404 response, this module will instead call `next()` to move on\nto the next middleware, allowing for stacking and fall-backs.\n\n#### Options\n\n##### dotfiles\n\n Set how \"dotfiles\" are treated when encountered. A dotfile is a file\nor directory that begins with a dot (\".\"). Note this check is done on\nthe path itself without checking if the path actually exists on the\ndisk. If `root` is specified, only the dotfiles above the root are\nchecked (i.e. the root itself can be within a dotfile when when set\nto \"deny\").\n\nThe default value is `'ignore'`.\n\n - `'allow'` No special treatment for dotfiles.\n - `'deny'` Send a 403 for any request for a dotfile.\n - `'ignore'` Pretend like the dotfile does not exist and call `next()`.\n\n##### etag\n\nEnable or disable etag generation, defaults to true.\n\n##### index\n\nBy default this module will send \"index.html\" files in response to a request\non a directory. To disable this set `false` or to supply a new index pass a\nstring or an array in preferred order.\n\n##### maxAge\n\nProvide a max-age in milliseconds for http caching, defaults to 0. This\ncan also be a string accepted by the [ms](https://www.npmjs.org/package/ms#readme)\nmodule.\n\n##### redirect\n\nRedirect to trailing \"/\" when the pathname is a dir. Defaults to `true`.\n\n##### setHeaders\n\nFunction to set custom headers on response.\n\n## Examples\n\n### Serve files with vanilla node.js http server\n\n```js\nvar finalhandler = require('finalhandler')\nvar http = require('http')\nvar serveStatic = require('serve-static')\n\n// Serve up public/ftp folder\nvar serve = serveStatic('public/ftp', {'index': ['index.html', 'index.htm']})\n\n// Create server\nvar server = http.createServer(function(req, res){\n var done = finalhandler(req, res)\n serve(req, res, done)\n})\n\n// Listen\nserver.listen(3000)\n```\n\n### Serve all files from ftp folder\n\n```js\nvar connect = require('connect')\nvar serveStatic = require('serve-static')\n\nvar app = connect()\n\napp.use(serveStatic('public/ftp', {'index': ['default.html', 'default.htm']}))\napp.listen(3000)\n```\n\n### Serve all files as downloads\n\n```js\nvar express = require('express')\nvar serveStatic = require('serve-static')\n\nvar app = express()\n\napp.use(serveStatic('public/ftp', {\n 'index': false,\n 'setHeaders': setHeaders\n}))\napp.listen(3000)\n\nfunction setHeaders(res, path) {\n res.attachment(path)\n}\n```\n\n## License\n\nThe MIT License (MIT)\n\nCopyright (c) 2014 Douglas Christopher Wilson\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n",
"readmeFilename": "Readme.md",
"bugs": {
"url": "https://github.com/expressjs/serve-static/issues"
},
"_id": "serve-static@1.3.1",
"_id": "serve-static@1.4.0",
"_from": "serve-static@*"
}
{
"name": "better-assert",
"version": "1.0.0",
"version": "1.0.1",
"description": "Better assertions for node, reporting the expr, filename, lineno etc",
"keywords": [
"assert",
......@@ -12,16 +12,32 @@
"name": "TJ Holowaychuk",
"email": "tj@vision-media.ca"
},
"contributors": [
{
"name": "TonyHe",
"email": "coolhzb@163.com"
},
{
"name": "ForbesLindesay"
}
],
"dependencies": {
"callsite": "1.0.0"
},
"repository": {
"type": "git",
"url": "https://github.com/visionmedia/better-assert.git"
},
"main": "index",
"engines": {
"node": "*"
},
"readme": "\n# better-assert\n\n Better c-style assertions using [callsite](https://github.com/visionmedia/callsite) for\n self-documenting failure messages.\n\n## Installation\n\n $ npm install better-assert\n\n## Example\n\n By default assertions are enabled, however the __NO_ASSERT__ environment variable \n will deactivate them when truthy.\n\n```js\nvar assert = require('better-assert');\n\ntest();\n\nfunction test() {\n var user = { name: 'tobi' };\n assert('tobi' == user.name);\n assert('number' == typeof user.age);\n}\n\nAssertionError: 'number' == typeof user.age\n at test (/Users/tj/projects/better-assert/example.js:9:3)\n at Object.<anonymous> (/Users/tj/projects/better-assert/example.js:4:1)\n at Module._compile (module.js:449:26)\n at Object.Module._extensions..js (module.js:467:10)\n at Module.load (module.js:356:32)\n at Function.Module._load (module.js:312:12)\n at Module.runMain (module.js:492:10)\n at process.startup.processNextTick.process._tickCallback (node.js:244:9)\n```\n\n## License \n\n(The MIT License)\n\nCopyright (c) 2012 TJ Holowaychuk &lt;tj@vision-media.ca&gt;\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n'Software'), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.",
"readmeFilename": "Readme.md",
"_id": "better-assert@1.0.0",
"bugs": {
"url": "https://github.com/visionmedia/better-assert/issues"
},
"_id": "better-assert@1.0.1",
"_from": "better-assert@~1.0.0",
"scripts": {}
}
{
"name": "better-assert",
"version": "1.0.0",
"version": "1.0.1",
"description": "Better assertions for node, reporting the expr, filename, lineno etc",
"keywords": [
"assert",
......@@ -12,16 +12,32 @@
"name": "TJ Holowaychuk",
"email": "tj@vision-media.ca"
},
"contributors": [
{
"name": "TonyHe",
"email": "coolhzb@163.com"
},
{
"name": "ForbesLindesay"
}
],
"dependencies": {
"callsite": "1.0.0"
},
"repository": {
"type": "git",
"url": "https://github.com/visionmedia/better-assert.git"
},
"main": "index",
"engines": {
"node": "*"
},
"readme": "\n# better-assert\n\n Better c-style assertions using [callsite](https://github.com/visionmedia/callsite) for\n self-documenting failure messages.\n\n## Installation\n\n $ npm install better-assert\n\n## Example\n\n By default assertions are enabled, however the __NO_ASSERT__ environment variable \n will deactivate them when truthy.\n\n```js\nvar assert = require('better-assert');\n\ntest();\n\nfunction test() {\n var user = { name: 'tobi' };\n assert('tobi' == user.name);\n assert('number' == typeof user.age);\n}\n\nAssertionError: 'number' == typeof user.age\n at test (/Users/tj/projects/better-assert/example.js:9:3)\n at Object.<anonymous> (/Users/tj/projects/better-assert/example.js:4:1)\n at Module._compile (module.js:449:26)\n at Object.Module._extensions..js (module.js:467:10)\n at Module.load (module.js:356:32)\n at Function.Module._load (module.js:312:12)\n at Module.runMain (module.js:492:10)\n at process.startup.processNextTick.process._tickCallback (node.js:244:9)\n```\n\n## License \n\n(The MIT License)\n\nCopyright (c) 2012 TJ Holowaychuk &lt;tj@vision-media.ca&gt;\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n'Software'), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.",
"readmeFilename": "Readme.md",
"_id": "better-assert@1.0.0",
"bugs": {
"url": "https://github.com/visionmedia/better-assert/issues"
},
"_id": "better-assert@1.0.1",
"_from": "better-assert@~1.0.0",
"scripts": {}
}
{
"name": "better-assert",
"version": "1.0.0",
"version": "1.0.1",
"description": "Better assertions for node, reporting the expr, filename, lineno etc",
"keywords": [
"assert",
......@@ -12,15 +12,31 @@
"name": "TJ Holowaychuk",
"email": "tj@vision-media.ca"
},
"contributors": [
{
"name": "TonyHe",
"email": "coolhzb@163.com"
},
{
"name": "ForbesLindesay"
}
],
"dependencies": {
"callsite": "1.0.0"
},
"repository": {
"type": "git",
"url": "https://github.com/visionmedia/better-assert.git"
},
"main": "index",
"engines": {
"node": "*"
},
"readme": "\n# better-assert\n\n Better c-style assertions using [callsite](https://github.com/visionmedia/callsite) for\n self-documenting failure messages.\n\n## Installation\n\n $ npm install better-assert\n\n## Example\n\n By default assertions are enabled, however the __NO_ASSERT__ environment variable \n will deactivate them when truthy.\n\n```js\nvar assert = require('better-assert');\n\ntest();\n\nfunction test() {\n var user = { name: 'tobi' };\n assert('tobi' == user.name);\n assert('number' == typeof user.age);\n}\n\nAssertionError: 'number' == typeof user.age\n at test (/Users/tj/projects/better-assert/example.js:9:3)\n at Object.<anonymous> (/Users/tj/projects/better-assert/example.js:4:1)\n at Module._compile (module.js:449:26)\n at Object.Module._extensions..js (module.js:467:10)\n at Module.load (module.js:356:32)\n at Function.Module._load (module.js:312:12)\n at Module.runMain (module.js:492:10)\n at process.startup.processNextTick.process._tickCallback (node.js:244:9)\n```\n\n## License \n\n(The MIT License)\n\nCopyright (c) 2012 TJ Holowaychuk &lt;tj@vision-media.ca&gt;\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n'Software'), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.",
"readmeFilename": "Readme.md",
"_id": "better-assert@1.0.0",
"bugs": {
"url": "https://github.com/visionmedia/better-assert/issues"
},
"_id": "better-assert@1.0.1",
"_from": "better-assert@~1.0.0"
}
......@@ -15,6 +15,10 @@ tail = new Tail("fileToTail");
tail.on("line", function(data) {
console.log(data);
});
tail.on("error", function(error) {
console.log('ERROR: ', error);
});
````
Tail accepts the line separator as second parameter. If nothing is passed it is defaulted to new line '\n'.
......
......@@ -15,7 +15,7 @@
],
"name": "tail",
"description": "tail a file in node",
"version": "0.3.5",
"version": "0.3.7",
"repository": {
"type": "git",
"url": "git://github.com/lucagrulla/node-tail.git"
......@@ -26,13 +26,13 @@
},
"dependencies": {},
"devDependencies": {
"coffee-script": "1.6.2"
"coffee-script": "1.7.1"
},
"readme": "#tail\n\nTo install:\n\n```bash\nnpm install tail\n```\n\n#Use:\n```javascript\nTail = require('tail').Tail;\n\ntail = new Tail(\"fileToTail\");\n\ntail.on(\"line\", function(data) {\n console.log(data);\n});\n````\n\nTail accepts the line separator as second parameter. If nothing is passed it is defaulted to new line '\\n'.\n\n```javascript\n\nvar lineSeparator= \"-\";\n\nnew Tail(\"fileToTail\",lineSeparator)\n```\n\nTail emits two type of events:\n\n* line \n```\nfunction(data){}\n```\n* error\n```\nfunction(exception){}\n```\n\nIf you simply want to stop the tail:\n\n```javascript\ntail.unwatch()\n```\n\nAnd to start watching again:\n```javascript\ntail.watch()\n```\n\n#Want to fork ?\n\nTail is written in [CoffeeScript](http://jashkenas.github.com/coffee-script/).\n\nThe Cakefile generates the javascript that is then published to npm.\n\n#License\nMIT. Please see License file for more details.\n",
"readme": "#tail\n\nTo install:\n\n```bash\nnpm install tail\n```\n\n#Use:\n```javascript\nTail = require('tail').Tail;\n\ntail = new Tail(\"fileToTail\");\n\ntail.on(\"line\", function(data) {\n console.log(data);\n});\n\ntail.on(\"error\", function(error) {\n console.log('ERROR: ', error);\n});\n````\n\nTail accepts the line separator as second parameter. If nothing is passed it is defaulted to new line '\\n'.\n\n```javascript\n\nvar lineSeparator= \"-\";\n\nnew Tail(\"fileToTail\",lineSeparator)\n```\n\nTail emits two type of events:\n\n* line \n```\nfunction(data){}\n```\n* error\n```\nfunction(exception){}\n```\n\nIf you simply want to stop the tail:\n\n```javascript\ntail.unwatch()\n```\n\nAnd to start watching again:\n```javascript\ntail.watch()\n```\n\n#Want to fork ?\n\nTail is written in [CoffeeScript](http://jashkenas.github.com/coffee-script/).\n\nThe Cakefile generates the javascript that is then published to npm.\n\n#License\nMIT. Please see License file for more details.\n",
"readmeFilename": "README.md",
"bugs": {
"url": "https://github.com/lucagrulla/node-tail/issues"
},
"_id": "tail@0.3.5",
"_id": "tail@0.3.7",
"_from": "tail@*"
}
......@@ -90,27 +90,24 @@ Tail = (function(_super) {
};
Tail.prototype.watchEvent = function(e) {
var _this = this;
var stats,
_this = this;
if (e === 'change') {
return fs.stat(this.filename, function(err, stats) {
if (err) {
_this.emit('error', err);
}
if (stats.size < _this.pos) {
_this.pos = stats.size;
}
if (stats.size > _this.pos) {
_this.queue.push({
start: _this.pos,
end: stats.size
});
_this.pos = stats.size;
if (_this.queue.length === 1) {
return _this.internalDispatcher.emit("next");
}
stats = fs.statSync(this.filename);
if (stats.size < this.pos) {
this.pos = stats.size;
}
if (stats.size > this.pos) {
this.queue.push({
start: this.pos,
end: stats.size
});
this.pos = stats.size;
if (this.queue.length === 1) {
return this.internalDispatcher.emit("next");
}
});
}
} else if (e === 'rename') {
this.unwatch();
return setTimeout((function() {
......
......@@ -143,7 +143,7 @@ ProxyServer.prototype.before = function(type, passName, callback) {
if(v.name === passName) i = idx;
})
if(!i) throw new Error('No such pass');
if(i === false) throw new Error('No such pass');
passes.splice(i, 0, callback);
};
......@@ -158,7 +158,7 @@ ProxyServer.prototype.after = function(type, passName, callback) {
if(v.name === passName) i = idx;
})
if(!i) throw new Error('No such pass');
if(i === false) throw new Error('No such pass');
passes.splice(i++, 0, callback);
};
{
"name": "http-proxy",
"version": "1.1.5",
"version": "1.1.6",
"repository": {
"type": "git",
"url": "https://github.com/nodejitsu/node-http-proxy.git"
......@@ -50,10 +50,10 @@
"bugs": {
"url": "https://github.com/nodejitsu/node-http-proxy/issues"
},
"_id": "http-proxy@1.1.5",
"_id": "http-proxy@1.1.6",
"dist": {
"shasum": "918a323d1f14677976670f557add4d00b43f2214"
"shasum": "aac9393db4d4bf9d548876148ccf2c0a92fcaad1"
},
"_from": "http-proxy@*",
"_resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.1.5.tgz"
"_resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.1.6.tgz"
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment