Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

restify

Package Overview
Dependencies
Maintainers
0
Versions
184
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

restify - npm Package Compare versions

Comparing version 0.2.10 to 0.2.11

16

lib/client.js

@@ -81,3 +81,3 @@ // Copyright 2011 Mark Cavage <mcavage@gmail.com> All rights reserved.

!(this.url.pathname === '/' &&
options.url[options.url.length-1] !== '/')) {
options.url[options.url.length - 1] !== '/')) {
this.path = this.url.pathname;

@@ -121,3 +121,3 @@ }

*
* @param {Object} optional options with:
* @param {Object} options (optional) with:
* - path: resource path.

@@ -128,3 +128,3 @@ * - body: a JS object that will get marshalled to JSON.

* - expect: expected HTTP status code. Defaults to 204.
* @callback {Function} (optional) callback of the form f(err, obj, headers).
* @param {Function} callback of the form f(err, obj, headers).
*/

@@ -165,3 +165,3 @@ RestClient.prototype.put = function(options, callback) {

* - expect: (optional) expected HTTP status code. Defaults to 200.
* @callback {Function} (optional) callback of the form function(err, headers).
* @param {Function} callback of the form function(err, headers).
*/

@@ -201,3 +201,3 @@ RestClient.prototype.post = function(options, callback) {

* - expect: (optional) expected HTTP status code. Defaults to 200.
* @callback {Function} (optional) callback of the form f(err, obj, headers).
* @param {Function} callback of the form f(err, obj, headers).
*/

@@ -237,3 +237,3 @@ RestClient.prototype.get = function(options, callback) {

* - expect: (optional) expected HTTP status code. Defaults to 204.
* @callback {Function} (optional) callback of the form function(err, headers).
* @param {Function} callback of the form function(err, headers).
*/

@@ -274,3 +274,3 @@ RestClient.prototype.del = function(options, callback) {

* - expect: (optional) expected HTTP status code. Defaults to 204.
* @callback {Function} (optional) callback of the form function(err, headers).
* @param {Function} callback of the form function(err, headers).
*/

@@ -461,3 +461,3 @@ RestClient.prototype.head = function(options, callback) {

opts.port = (self.url.port ||
(self.url.protocol === "https:" ? 443 : 80)).toString();
(self.url.protocol === 'https:' ? 443 : 80)).toString();
} else {

@@ -464,0 +464,0 @@ opts.socketPath = self.socketPath.toString();

@@ -299,3 +299,3 @@ // Copyright 2011 Mark Cavage <mcavage@gmail.com> All rights reserved.

var handlers = utils.mergeFunctionArguments(args, offset);
var handlers = utils.mergeFunctionArguments(args, offset);

@@ -302,0 +302,0 @@ return this._mount('HEAD', url, handlers, version);

@@ -15,3 +15,3 @@ // Copyright 2011 Mark Cavage <mcavage@gmail.com> All rights reserved.

// createThrottle: require('./throttle').createThrottle,
createThrottle: require('./throttle').createThrottle,

@@ -18,0 +18,0 @@ HttpCodes: require('./http_codes'),

@@ -164,3 +164,3 @@ // Copyright 2011 Mark Cavage <mcavage@gmail.com> All rights reserved.

req.authorization = {};
req.username = 'anonymous';
if (!req.headers.authorization) {

@@ -171,3 +171,3 @@ log.trace('No authorization header present.');

var pieces = req.headers.authorization.split(' ', 2);
var pieces = req.headers.authorization.split(' ', 2);
if (!pieces || pieces.length !== 2) {

@@ -174,0 +174,0 @@ res.sendError(newError({

// Copyright 2011 Mark Cavage <mcavage@gmail.com> All rights reserved.
var newError = require('./error').newError;
var log = require('./log');
var HttpCodes = require('./http_codes');

@@ -9,2 +12,23 @@ var RestCodes = require('./rest_codes');

/**
* Creates an API rate limiter that can be plugged into the standard
* restify request handling pipeline.
*
* This throttle gives you two options on which to throttle:
* username and IP address. IP address is an exact match (i.e. a /32),
* so keep that in mind if using it. In both cases, there's a blanket
* policy put in place by `options.requests` and `options.seconds`.
* Which obviously translates to M requetss in N seconds. On the `options`
* object ip and username are treated as an XOR.
*
* @param {Object} options required options with:
* - {Number} requests (required).
* - {Number} seconds (required).
* - {String} ip (optional).
* - {String} username (optional).
* - {Object} overrides (optional).
*
* @return {Function} of type f(req, res, next) to be plugged into a route.
* @throws {TypeError} on bad input.
*/
createThrottle: function(options) {

@@ -18,4 +42,2 @@ if (!options) throw new TypeError('options is required');

var requests = options.requests;
var seconds = options.seconds;
var checked = new Date().getTime();

@@ -25,3 +47,7 @@ var hash = {};

return function(req, res, next) {
var attr;
var requests = options.requests;
var seconds = options.seconds;
var rate = requests / seconds;
var attr = null;
if (options.ip) {

@@ -39,24 +65,50 @@ attr = req.connection.remoteAddress;

} else {
log.trace('throttle(%o): not actionable, skipping', options);
return next();
}
if (options.overrides) {
if (options.overrides[attr] &&
options.overrides[attr].requests !== undefined &&
options.overrides[attr].seconds !== undefined) {
requests = options.overrides[attr].requests;
seconds = options.overrides[attr].seconds;
log.trace('throttle(%o): attr=%s, using overrides r=%d, s=%d',
options, attr, requests, seconds);
}
}
if (seconds === 0) {
log.trace('throttle(%o): attr=%s, seconds=0. unlimited',
options, attr);
return next();
}
if (!hash[attr])
hash[attr] = options.requests;
hash[attr] = requests + 1;
var now = new Date().getTime();
var delta = now - checked;
var delta = (now - checked) / 1000; // time since last check
checked = now;
hash[attr] += delta * (requests/seconds);
if (hash[attr] > requests) {
hash[attr] = requests;
} else if (hash[attr] < 1.0) {
if (delta > seconds) {
log.trace('throttle(%o): attr=%s => resetting counter');
hash[attr] = requests + 1;
return next();
}
hash[attr] -= 1;
log.trace('throttle(%o): attr=%s, current=%d, requests=%d',
options, attr, hash[attr], requests);
if (hash[attr] <= 0) {
return res.sendError(newError({
httpCode: HttpCodes.Forbidden,
restCode: RestCodes.RequestThrottled,
message: 'You have exceeded ' + requests + 'r/' + seconds + 's'
message: 'You have exceeded ' + requests +
' requests per ' + seconds + ' seconds.'
}));
} else {
hash[attr] -= 1.0;
return next();
}
return next();
};

@@ -63,0 +115,0 @@ }

@@ -42,3 +42,3 @@ // Copyright 2011 Mark Cavage <mcavage@gmail.com> All rights reserved.

mergeFunctionArguments: function (argv, offset) {
mergeFunctionArguments: function(argv, offset) {
var handlers = [];

@@ -45,0 +45,0 @@

{
"name": "restify",
"description": "REST framework specifically meant for web service APIs",
"version": "0.2.10",
"version": "0.2.11",
"repository": {

@@ -18,3 +18,3 @@ "type": "git",

"scripts": {
"pretest": "./node_modules/.bin/jshint lib tst",
"pretest": "./node_modules/.bin/jshint lib tst && which gjslint; if [[ \"$?\" = 0 ]] ; then gjslint --nojsdoc -r . -x lib/sprintf.js -e node_modules; else echo \"Missing gjslint. Skipping lint\"; fi",
"test": "./node_modules/.bin/whiskey --timeout 2000 -t \"`find tst -name *.test.js | xargs`\""

@@ -21,0 +21,0 @@ },

@@ -184,3 +184,3 @@ // Copyright 2011 Mark Cavage <mcavage@gmail.com> All rights reserved.

var content = '\u00bd + \u00bc = \u00be';
var opts = common.newOptions(socket, '/test/' + uuid());
var opts = common.newOptions(socket, '/test/' + uuid());
opts.method = 'POST';

@@ -187,0 +187,0 @@ opts.headers['Content-Type'] = 'text/plain';

@@ -31,9 +31,26 @@ // Copyright 2011 Mark Cavage <mcavage@gmail.com> All rights reserved.

seconds: 2,
username: true
username: true,
overrides: {
'admin': {
requests: 0,
seconds: 0
},
'special': {
requests: 3,
seconds: 1
}
}
});
server.get('/test/:name', throttle, function(req, res, next) {
res.send(200);
return next();
});
server.get('/test/:name',
function(req, res, next) {
req.username = req.uriParams.name;
return next();
},
throttle,
function(req, res, next) {
res.send(200);
return next();
}
);

@@ -47,6 +64,4 @@ server.listen(socket, function() {

exports.test_ok = function(test, assert) {
var opts = common.newOptions(socket, '/test/unit');
var opts = common.newOptions(socket, '/test/throttleMe');
opts.method = 'GET';
opts.headers.authorization = 'Basic ' +
new Buffer(username + ':' + password, 'utf8').toString('base64');

@@ -61,4 +76,4 @@ http.request(opts, function(res) {

exports.test_no_auth = function(test, assert) {
var opts = common.newOptions(socket, '/test/unit');
exports.test_throttled = function(test, assert) {
var opts = common.newOptions(socket, '/test/throttleMe');
opts.method = 'GET';

@@ -68,4 +83,9 @@

common.checkResponse(assert, res);
assert.equal(res.statusCode, 401);
test.finish();
assert.equal(res.statusCode, 403);
common.checkContent(assert, res, function() {
assert.ok(res.params);
assert.equal(res.params.code, 'RequestThrottled');
assert.ok(res.params.message);
setTimeout(function() { test.finish(); }, 1000);
});
}).end();

@@ -75,11 +95,9 @@ };

exports.test_forbidden = function(test, assert) {
var opts = common.newOptions(socket, '/test/unit');
exports.test_ok_after_window = function(test, assert) {
var opts = common.newOptions(socket, '/test/throttleMe');
opts.method = 'GET';
opts.headers.authorization = 'Basic ' +
new Buffer('...:' + password, 'utf8').toString('base64');
http.request(opts, function(res) {
common.checkResponse(assert, res);
assert.equal(res.statusCode, 403);
assert.equal(res.statusCode, 200);
test.finish();

@@ -90,11 +108,14 @@ }).end();

exports.test_bad_scheme = function(test, assert) {
var opts = common.newOptions(socket, '/test/unit');
exports.test_override_limited = function(test, assert) {
var opts = common.newOptions(socket, '/test/special');
opts.method = 'GET';
opts.headers.authorization = uuid();
http.request(opts, function(res) {
common.checkResponse(assert, res);
assert.equal(res.statusCode, 400);
test.finish();
assert.equal(res.statusCode, 200);
http.request(opts, function(res) {
common.checkResponse(assert, res);
assert.equal(res.statusCode, 200);
test.finish();
}).end();
}).end();

@@ -104,11 +125,14 @@ };

exports.test_bad_basic = function(test, assert) {
var opts = common.newOptions(socket, '/test/unit');
exports.test_override_unlimited = function(test, assert) {
var opts = common.newOptions(socket, '/test/admin');
opts.method = 'GET';
opts.headers.authorization = 'Basic ' + uuid();
http.request(opts, function(res) {
common.checkResponse(assert, res);
assert.equal(res.statusCode, 400);
test.finish();
assert.equal(res.statusCode, 200);
http.request(opts, function(res) {
common.checkResponse(assert, res);
assert.equal(res.statusCode, 200);
test.finish();
}).end();
}).end();

@@ -115,0 +139,0 @@ };

@@ -136,4 +136,4 @@ // Copyright 2011 Mark Cavage <mcavage@gmail.com> All rights reserved.

server.get('/', function(req, res, next) { return res.send(200) ; });
server.get('1.2.4', '/', function(req, res, next) { return res.send(201) ; });
server.get('/', function(req, res, next) { return res.send(200); });
server.get('1.2.4', '/', function(req, res, next) { return res.send(201); });
server.listen(socket, function() {

@@ -140,0 +140,0 @@ var opts = common.newOptions(socket, '/');

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc