Comparing version 2.8.5 to 3.0.0
# restify Changelog | ||
## not yet released | ||
## 3.0.0 | ||
- Bumping major because of #753 | ||
## 2.9.0 | ||
- #688 Fix various throttle bugs | ||
- #691 Fix an issue where posting with text/csv content type crashes Restify | ||
- #693 Support multiple response header values | ||
- #704 Allow partial regex for named parameters | ||
- #726 Allow per-request agent overrides | ||
- #726 Ebanle `{agent: false}` option override per request | ||
- #727 Fix JSON body parser behavior when request body is null | ||
- #727 Fix a bug when `req.body === null` | ||
- #731 SVG badges in README | ||
- #734 Add API to track timers for nested handlers | ||
- #744 Fix `request.isUpload` for PATCH requests | ||
- #751 Fix `server.url` property when using IPv6 | ||
- #758 Switch to UUID v4 | ||
- #758 Use v4 UUIDs for `[x-]request-id` | ||
- #759 Documentation fix | ||
- #762 `res.noCache()` API to prevent all caching | ||
- #767 Prefer the existing `err` serializer for audit logging | ||
- Update dtrace-provider dependency | ||
- #753 **BREAKING** Include `err` parameter for all \*Error events: | ||
Error events will all have the signature `function (req, res, err, cb)` to | ||
become consistent with the handling functionality introduced in 2.8.5. | ||
Error handlers using the `function (req, res, cb)` signature must be updated. | ||
## 2.8.5 | ||
@@ -6,0 +33,0 @@ |
@@ -517,3 +517,3 @@ // Copyright 2012 Mark Cavage, Inc. All rights reserved. | ||
var opts = { | ||
agent: options.agent || self.agent, | ||
agent: options.agent !== undefined ? options.agent : self.agent, | ||
ca: options.ca || self.ca, | ||
@@ -520,0 +520,0 @@ cert: options.cert || self.cert, |
@@ -25,7 +25,12 @@ // Copyright 2012 Mark Cavage, Inc. All rights reserved. | ||
assert.object(options.log, 'options.log'); | ||
var errSerializer = bunyan.stdSerializers.err; | ||
if (options.log.serializers && options.log.serializers.err) { | ||
errSerializer = options.log.serializers.err; | ||
} | ||
var log = options.log.child({ | ||
audit: true, | ||
serializers: { | ||
err: bunyan.stdSerializers.err, | ||
err: errSerializer, | ||
req: function auditRequestSerializer(req) { | ||
@@ -32,0 +37,0 @@ if (!req) |
@@ -49,35 +49,27 @@ /** | ||
var parsedBody = []; | ||
var parserOptions = { | ||
delimiter: delimiter, | ||
quote: quote, | ||
escape: escape, | ||
columns: columns | ||
}; | ||
csv() | ||
.from(req.body, { | ||
delimiter: delimiter, | ||
quote: quote, | ||
escape: escape, | ||
columns: columns | ||
}) | ||
.on('record', function (row, index) { | ||
csv.parse(req.body, parserOptions, function (err, parsedBody) { | ||
if (err) { | ||
return (next(err)); | ||
} | ||
// Add an "index" property to every row | ||
parsedBody.forEach(function (row, index) { | ||
row.index = index; | ||
parsedBody.push(row); | ||
}) | ||
.on('end', function (count) { | ||
req.body = parsedBody; | ||
return (next()); | ||
}) | ||
.on('error', function (error) { | ||
return (next(error)); | ||
}); | ||
req.body = parsedBody; | ||
return (next()); | ||
}); | ||
} | ||
var chain = []; | ||
if (!options.bodyReader) { | ||
chain.push(bodyReader(options)); | ||
} | ||
chain.push(parseFieldedText); | ||
return (parseFieldedText); | ||
return (chain); | ||
} | ||
module.exports = fieldedTextParser; |
@@ -45,3 +45,3 @@ // Copyright 2012 Mark Cavage, Inc. All rights reserved. | ||
req.params = params; | ||
} else if (typeof (params) === 'object') { | ||
} else if (typeof (params) === 'object' && params !== null) { | ||
Object.keys(params).forEach(function (k) { | ||
@@ -55,3 +55,3 @@ var p = req.params[k]; | ||
} else { | ||
req.params = params; | ||
req.params = params || req.params; | ||
} | ||
@@ -58,0 +58,0 @@ } else { |
@@ -193,4 +193,2 @@ // Copyright 2012 Mark Cavage <mcavage@gmail.com> All rights reserved. | ||
var burst = options.burst; | ||
var rate = options.rate; | ||
var table = options.tokensTable || | ||
@@ -201,2 +199,5 @@ new TokenTable({size: options.maxKeys}); | ||
var attr; | ||
var burst = options.burst; | ||
var rate = options.rate; | ||
if (options.ip) { | ||
@@ -252,4 +253,2 @@ attr = req.connection.remoteAddress; | ||
// Until https://github.com/joyent/node/pull/2371 is in | ||
var msg = sprintf(MESSAGE, rate); | ||
@@ -256,0 +255,0 @@ return (next(new TooManyRequestsError(msg))); |
@@ -12,2 +12,3 @@ // Copyright 2012 Mark Cavage, Inc. All rights reserved. | ||
var dtrace = require('./dtrace'); | ||
var utils = require('./utils'); | ||
@@ -50,4 +51,4 @@ | ||
var protocol = this.secure ? 'https://' : 'http://'; | ||
var hostname = this.headers['host']; | ||
return (url.resolve(protocol + hostname + this.path + '/', path)); | ||
var hostname = this.headers.host; | ||
return (url.resolve(protocol + hostname + this.path() + '/', path)); | ||
}; | ||
@@ -150,3 +151,3 @@ | ||
this.headers['x-request-id'] || | ||
uuid.v1(); | ||
uuid.v4(); | ||
@@ -283,3 +284,3 @@ return (this._id); | ||
var m = this.method; | ||
return (m === 'PATH' || m === 'POST' || m === 'PUT'); | ||
return (m === 'PATCH' || m === 'POST' || m === 'PUT'); | ||
}; | ||
@@ -310,1 +311,59 @@ | ||
}; | ||
/** | ||
* Start the timer for a request handler function. You must explicitly invoke | ||
* endHandlerTimer() after invoking this function. Otherwise timing information | ||
* will be inaccurate. | ||
* @param String handlerName The name of the handler. | ||
*/ | ||
Request.prototype.startHandlerTimer = function startHandlerTimer(handlerName) | ||
{ | ||
var self = this; | ||
// For nested handlers, we prepend the top level handler func name | ||
var name = (self._currentHandler === handlerName ? | ||
handlerName : self._currentHandler + '-' + handlerName); | ||
if (!self._timerMap) | ||
self._timerMap = {}; | ||
self._timerMap[name] = process.hrtime(); | ||
dtrace._rstfy_probes['handler-start'].fire(function () { | ||
return ([ | ||
self.serverName, | ||
self._currentRoute, // set in server._run | ||
name, | ||
self._dtraceId | ||
]); | ||
}); | ||
}; | ||
/** | ||
* Stop the timer for a request handler function. | ||
* @param String handlerName The name of the handler. | ||
*/ | ||
Request.prototype.endHandlerTimer = function endHandlerTimer(handlerName) | ||
{ | ||
var self = this; | ||
// For nested handlers, we prepend the top level handler func name | ||
var name = (self._currentHandler === handlerName ? | ||
handlerName : self._currentHandler + '-' + handlerName); | ||
if (!self.timers) | ||
self.timers = []; | ||
self._timerMap[name] = process.hrtime(self._timerMap[name]); | ||
self.timers.push({ | ||
name: name, | ||
time: self._timerMap[name] | ||
}); | ||
dtrace._rstfy_probes['handler-done'].fire(function () { | ||
return ([ | ||
self.serverName, | ||
self._currentRoute, // set in server._run | ||
name, | ||
self._dtraceId | ||
]); | ||
}); | ||
}; |
@@ -40,2 +40,16 @@ // Copyright 2012 Mark Cavage, Inc. All rights reserved. | ||
Response.prototype.noCache = function noCache() { | ||
// HTTP 1.1 | ||
this.header('Cache-Control', 'no-cache, no-store, must-revalidate'); | ||
// HTTP 1.0 | ||
this.header('Pragma', 'no-cache'); | ||
// Proxies | ||
this.header('Expires', '0'); | ||
return (this); | ||
}; | ||
Response.prototype.charSet = function charSet(type) { | ||
@@ -131,2 +145,12 @@ assert.string(type, 'charset'); | ||
var current = this.getHeader(name); | ||
if (current) { | ||
if (Array.isArray(current)) { | ||
current.push(value); | ||
value = current; | ||
} else { | ||
value = [current, value]; | ||
} | ||
} | ||
this.setHeader(name, value); | ||
@@ -133,0 +157,0 @@ return (value); |
@@ -92,12 +92,20 @@ // Copyright 2012 Mark Cavage, Inc. All rights reserved. | ||
if (frag.charAt(0) === ':') { | ||
if (options.urlParamPattern) { | ||
pattern += '(' + options.urlParamPattern + ')'; | ||
var label = frag; | ||
var index = frag.indexOf('('); | ||
var subexp; | ||
if (index === -1) { | ||
if (options.urlParamPattern) { | ||
subexp = options.urlParamPattern; | ||
} else { | ||
subexp = '[^/]*'; | ||
} | ||
} else { | ||
pattern += '([^/]*)'; | ||
label = frag.substring(0, index); | ||
subexp = frag.substring(index+1, frag.length-1); | ||
} | ||
params.push(frag.slice(1)); | ||
pattern += '(' + subexp + ')'; | ||
params.push(label.slice(1)); | ||
} else { | ||
pattern += frag; | ||
} | ||
return (true); | ||
@@ -175,3 +183,2 @@ }); | ||
} | ||
return ('/' + encodeURIComponent(params[key])); | ||
@@ -189,6 +196,6 @@ } | ||
var _url = route.spec.path.replace(/\/:([^/]+)/g, pathItem); | ||
var _path = route.spec.path; | ||
var _url = _path.replace(/\/:([A-Za-z0-9_]+)(\([^\\]+\))?/g, pathItem); | ||
var items = Object.keys(query || {}).map(queryItem); | ||
var queryString = items.length > 0 ? ('?' + items.join('&')) : ''; | ||
return (_url + queryString); | ||
@@ -497,3 +504,3 @@ }; | ||
if (preflight(res.methods)) { | ||
callback(null, { name: 'preflight' }); | ||
callback(null, {name: 'preflight'}); | ||
return; | ||
@@ -500,0 +507,0 @@ } |
@@ -148,3 +148,3 @@ // Copyright 2012 Mark Cavage, Inc. All rights reserved. | ||
if (server.listeners(name).length > 0) { | ||
server.emit(name, req, res, once(function () { | ||
server.emit(name, req, res, err, once(function () { | ||
server.emit('after', req, res, null); | ||
@@ -283,3 +283,4 @@ })); | ||
if (addr) { | ||
str += addr.address; | ||
str += addr.family === 'IPv6' ? | ||
'[' + addr.address + ']' : addr.address; | ||
str += ':'; | ||
@@ -604,2 +605,22 @@ str += addr.port; | ||
name = null; | ||
this.router.find(req, res, function onRoute(err, route, ctx) { | ||
var r = route ? route.name : null; | ||
if (err) { | ||
if (optionsError(err, req, res)) { | ||
self.emit('after', req, res, err); | ||
} else { | ||
emitRouteError(self, req, res, err); | ||
} | ||
} else if (r === 'preflight') { | ||
res.writeHead(200); | ||
res.end(); | ||
self.emit('after', req, res, null); | ||
} else if (!r || !self.routes[r]) { | ||
err = new ResourceNotFoundError(req.path()); | ||
emitRouteError(self, res, res, err); | ||
} else { | ||
cb(route, ctx); | ||
} | ||
}); | ||
} else { | ||
@@ -614,22 +635,2 @@ this.router.get(name, req, function (err, route, ctx) { | ||
} | ||
this.router.find(req, res, function onRoute(err, route, ctx) { | ||
var r = route ? route.name : null; | ||
if (err) { | ||
if (optionsError(err, req, res)) { | ||
self.emit('after', req, res, err); | ||
} else { | ||
emitRouteError(self, req, res, err); | ||
} | ||
} else if (r === 'preflight') { | ||
res.writeHead(200); | ||
res.end(); | ||
self.emit('after', req, res, null); | ||
} else if (!r || !self.routes[r]) { | ||
err = new ResourceNotFoundError(req.path()); | ||
emitRouteError(self, res, res, err); | ||
} else { | ||
cb(route, ctx); | ||
} | ||
}); | ||
}; | ||
@@ -653,5 +654,13 @@ | ||
var id = dtrace.nextId(); | ||
req._dtraceId = id; | ||
if (!req._anonFuncCount) { | ||
// Counter used to keep track of anonymous functions. Used when a | ||
// handler function is anonymous. This ensures we're using a | ||
// monotonically increasing int for anonymous handlers through out the | ||
// the lifetime of this request | ||
req._anonFuncCount = 0; | ||
} | ||
var log = this.log; | ||
var self = this; | ||
var t; | ||
var handlerName = null; | ||
var errName; | ||
@@ -679,3 +688,3 @@ var emittedError = false; | ||
done = true; | ||
} else if (typeof (arg) === 'string') { | ||
} else if (typeof (arg) === 'string') { // GH-193, allow redirect | ||
if (req._rstfy_chained_route) { | ||
@@ -691,3 +700,4 @@ var _e = new errors.InternalError(); | ||
self._route(req, res, arg, function (r, ctx) { | ||
// Stop running the rest of this route since we're redirecting | ||
return self._route(req, res, arg, function (r, ctx) { | ||
req.context = req.params = ctx; | ||
@@ -706,2 +716,6 @@ req.route = r.spec; | ||
req._rstfy_chained_route = true; | ||
// Need to fire DTrace done for previous handler here too. | ||
if ((i + 1) > 0 && chain[i] && !chain[i]._skip) { | ||
req.endHandlerTimer(handlerName); | ||
} | ||
self._run(req, res, r, _chain, cb); | ||
@@ -717,16 +731,3 @@ }); | ||
if ((i + 1) > 0 && chain[i] && !chain[i]._skip) { | ||
var _name = chain[i].name || ('handler-' + i); | ||
req.timers.push({ | ||
name: _name, | ||
time: process.hrtime(t) | ||
}); | ||
dtrace._rstfy_probes['handler-done'].fire(function () { | ||
return ([ | ||
self.name, | ||
route !== null ? route.name : 'pre', | ||
_name, | ||
id | ||
]); | ||
}); | ||
req.endHandlerTimer(handlerName); | ||
} | ||
@@ -739,14 +740,10 @@ | ||
t = process.hrtime(); | ||
if (log.trace()) | ||
log.trace('running %s', chain[i].name || '?'); | ||
dtrace._rstfy_probes['handler-start'].fire(function () { | ||
return ([ | ||
self.name, | ||
route !== null ? route.name : 'pre', | ||
chain[i].name || ('handler-' + i), | ||
id | ||
]); | ||
}); | ||
req._currentRoute = (route !== null ? route.name : 'pre'); | ||
handlerName = (chain[i].name || | ||
('handler-' + req._anonFuncCount++)); | ||
req._currentHandler = handlerName; | ||
req.startHandlerTimer(handlerName); | ||
@@ -774,3 +771,3 @@ var n = once(next); | ||
// don't return cb here if we emit an error since we will cb after the | ||
// Don't return cb here if we emit an error since we will cb after the | ||
// handler fires. | ||
@@ -798,3 +795,2 @@ if (!emittedError) { | ||
req.timers = []; | ||
d = domain.create(); | ||
@@ -818,2 +814,3 @@ d.add(req); | ||
req._time = res._time = Date.now(); | ||
req.serverName = this.name; | ||
@@ -826,3 +823,1 @@ res.acceptable = this.acceptable; | ||
}; | ||
// vim: set et ts=8 sts=8 sw=8: |
@@ -180,3 +180,1 @@ // Copyright (c) 2013, Joyent, Inc. All rights reserved. | ||
}; | ||
// vim: set et ts=8 sts=8 sw=8: |
172
package.json
{ | ||
"author": "Mark Cavage <mcavage@gmail.com>", | ||
"contributors": [ | ||
"Nathanael Anderson", | ||
"Adam Argo", | ||
"Dominic Barnes", | ||
"Josh Clulow", | ||
"Jonathan Dahan", | ||
"Domenic Denicola", | ||
"Bryan Donovan", | ||
"Paul Bouzakis", | ||
"Shaun Berryman", | ||
"Ben Hale", | ||
"Ben Howes", | ||
"Ben Hutchison", | ||
"Erik Kristensen", | ||
"Domikik Lessel", | ||
"Steve Mason", | ||
"Trent Mick", | ||
"Gergely Nemeth", | ||
"Colin O'Brien", | ||
"Falco Nogatz", | ||
"Pedro Palazón", | ||
"Andrew Robinson", | ||
"Isaac Schlueter", | ||
"Andrew Sliwinski", | ||
"Richardo Stuven", | ||
"Matt Smillie", | ||
"Diego Torres", | ||
"Mike Williams", | ||
"Brian Pin", | ||
"Ben Doerr", | ||
"Patrick Mooney", | ||
"Yunong Xiao" | ||
], | ||
"name": "restify", | ||
"homepage": "http://mcavage.github.com/node-restify", | ||
"description": "REST framework", | ||
"version": "2.8.5", | ||
"repository": { | ||
"type": "git", | ||
"url": "git://github.com/mcavage/node-restify.git" | ||
}, | ||
"main": "lib/index.js", | ||
"directories": { | ||
"lib": "./lib" | ||
}, | ||
"bin": { | ||
"report-latency": "./bin/report-latency" | ||
}, | ||
"engines": { | ||
"node": ">=0.10" | ||
}, | ||
"dependencies": { | ||
"assert-plus": "^0.1.5", | ||
"backoff": "^2.4.0", | ||
"bunyan": "^1.2.3", | ||
"csv": "^0.4.0", | ||
"deep-equal": "^0.2.1", | ||
"escape-regexp-component": "^1.0.2", | ||
"formidable": "^1.0.14", | ||
"http-signature": "^0.10.0", | ||
"keep-alive-agent": "^0.0.1", | ||
"lru-cache": "^2.5.0", | ||
"mime": "^1.2.11", | ||
"negotiator": "^0.4.5", | ||
"node-uuid": "^1.4.1", | ||
"once": "^1.3.0", | ||
"qs": "^1.0.0", | ||
"semver": "^2.3.0", | ||
"spdy": "^1.26.5", | ||
"tunnel-agent": "^0.4.0", | ||
"verror": "^1.4.0" | ||
}, | ||
"optionalDependencies": { | ||
"dtrace-provider": "^0.3.1" | ||
}, | ||
"devDependencies": { | ||
"cover": "^0.2.9", | ||
"filed": "^0.1.0", | ||
"nodeunit": "^0.9.0", | ||
"watershed": "^0.3.0" | ||
}, | ||
"scripts": { | ||
"test": "nodeunit ./test" | ||
} | ||
"author": "Mark Cavage <mcavage@gmail.com>", | ||
"contributors": [ | ||
"Nathanael Anderson", | ||
"Adam Argo", | ||
"Dominic Barnes", | ||
"Josh Clulow", | ||
"Jonathan Dahan", | ||
"Domenic Denicola", | ||
"Bryan Donovan", | ||
"Paul Bouzakis", | ||
"Shaun Berryman", | ||
"Ben Hale", | ||
"Ben Howes", | ||
"Ben Hutchison", | ||
"Erik Kristensen", | ||
"Domikik Lessel", | ||
"Steve Mason", | ||
"Trent Mick", | ||
"Gergely Nemeth", | ||
"Colin O'Brien", | ||
"Falco Nogatz", | ||
"Pedro Palazón", | ||
"Andrew Robinson", | ||
"Isaac Schlueter", | ||
"Andrew Sliwinski", | ||
"Richardo Stuven", | ||
"Matt Smillie", | ||
"Armin Tamzarian", | ||
"Diego Torres", | ||
"Mike Williams", | ||
"Brian Pin", | ||
"Ben Doerr", | ||
"Patrick Mooney", | ||
"Yunong Xiao", | ||
"Guillaume Chauvet" | ||
], | ||
"name": "restify", | ||
"homepage": "http://mcavage.github.com/node-restify", | ||
"description": "REST framework", | ||
"version": "3.0.0", | ||
"repository": { | ||
"type": "git", | ||
"url": "git://github.com/mcavage/node-restify.git" | ||
}, | ||
"main": "lib/index.js", | ||
"directories": { | ||
"lib": "./lib" | ||
}, | ||
"bin": { | ||
"report-latency": "./bin/report-latency" | ||
}, | ||
"engines": { | ||
"node": ">=0.10" | ||
}, | ||
"dependencies": { | ||
"assert-plus": "^0.1.5", | ||
"backoff": "^2.4.0", | ||
"bunyan": "1.3.4", | ||
"csv": "^0.4.0", | ||
"deep-equal": "^0.2.1", | ||
"escape-regexp-component": "^1.0.2", | ||
"formidable": "^1.0.14", | ||
"http-signature": "^0.10.0", | ||
"keep-alive-agent": "^0.0.1", | ||
"lru-cache": "^2.5.0", | ||
"mime": "^1.2.11", | ||
"negotiator": "^0.4.5", | ||
"node-uuid": "^1.4.1", | ||
"once": "^1.3.0", | ||
"qs": "^1.0.0", | ||
"semver": "^2.3.0", | ||
"spdy": "^1.26.5", | ||
"tunnel-agent": "^0.4.0", | ||
"verror": "^1.4.0" | ||
}, | ||
"optionalDependencies": { | ||
"dtrace-provider": "^0.4.0" | ||
}, | ||
"devDependencies": { | ||
"cover": "^0.2.9", | ||
"filed": "^0.1.0", | ||
"nodeunit": "^0.9.0", | ||
"watershed": "^0.3.0" | ||
}, | ||
"scripts": { | ||
"test": "make prepush" | ||
} | ||
} |
# restify | ||
[![Build Status](https://travis-ci.org/mcavage/node-restify.png)](https://travis-ci.org/mcavage/node-restify) | ||
[![Gitter chat](https://badges.gitter.im/mcavage/node-restify.png)](https://gitter.im/mcavage/node-restify) | ||
[![Dependency Status](https://david-dm.org/mcavage/node-restify.png)](https://david-dm.org/mcavage/node-restify) | ||
[![devDependency Status](https://david-dm.org/mcavage/node-restify/dev-status.png)](https://david-dm.org/mcavage/node-restify#info=devDependencies) | ||
[![Build Status](https://travis-ci.org/mcavage/node-restify.svg)](https://travis-ci.org/mcavage/node-restify) | ||
[![Gitter chat](https://badges.gitter.im/mcavage/node-restify.svg)](https://gitter.im/mcavage/node-restify) | ||
[![Dependency Status](https://david-dm.org/mcavage/node-restify.svg)](https://david-dm.org/mcavage/node-restify) | ||
[![devDependency Status](https://david-dm.org/mcavage/node-restify/dev-status.svg)](https://david-dm.org/mcavage/node-restify#info=devDependencies) | ||
@@ -13,2 +13,5 @@ | ||
Join us on IRC at `irc.freenode.net` in the `#restify` channel for real-time | ||
chat and support. | ||
# Usage | ||
@@ -15,0 +18,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
184844
4733
92
9
+ Addedbunyan@1.3.4(transitive)
+ Addeddtrace-provider@0.4.0(transitive)
+ Addednan@1.5.3(transitive)
- Removedbunyan@1.8.15(transitive)
- Removeddtrace-provider@0.3.20.8.8(transitive)
- Removedmoment@2.30.1(transitive)
- Removednan@1.3.02.22.0(transitive)
Updatedbunyan@1.3.4