Merge pull request #109 from seejohnrun/rate_limiting

Added user-configurable rate limiting
This commit is contained in:
John Crepezzi 2016-03-10 11:44:57 -10:00
commit 6835eef468
4 changed files with 82 additions and 38 deletions

View File

@ -46,6 +46,16 @@ STDOUT. Check the README there for more details and usages.
* `storage` - storage options (see below) * `storage` - storage options (see below)
* `logging` - logging preferences * `logging` - logging preferences
* `keyGenerator` - key generator options (see below) * `keyGenerator` - key generator options (see below)
* `rateLimits` - settings for rate limiting (see below)
## Rate Limiting
When present, the `rateLimits` option enables built-in rate limiting courtesy
of `connect-ratelimit`. Any of the options supported by that library can be
used and set in `config.json`.
See the README for [connect-ratelimit](https://github.com/dharmafly/connect-ratelimit)
for more information!
## Key Generation ## Key Generation

View File

@ -23,6 +23,15 @@
"type": "phonetic" "type": "phonetic"
}, },
"rateLimits": {
"categories": {
"normal": {
"totalRequests": 500,
"every": 60000
}
}
},
"storage": { "storage": {
"type": "redis", "type": "redis",
"host": "0.0.0.0", "host": "0.0.0.0",

View File

@ -14,8 +14,11 @@
}, },
"main": "haste", "main": "haste",
"dependencies": { "dependencies": {
"connect-ratelimit": "0.0.7",
"connect-route": "0.1.5",
"connect": "3.4.1",
"st": "1.1.0",
"winston": "0.6.2", "winston": "0.6.2",
"connect": "1.9.2",
"redis-url": "0.1.0", "redis-url": "0.1.0",
"redis": "0.8.1", "redis": "0.8.1",
"uglify-js": "1.3.3", "uglify-js": "1.3.3",

View File

@ -4,6 +4,9 @@ var fs = require('fs');
var winston = require('winston'); var winston = require('winston');
var connect = require('connect'); var connect = require('connect');
var route = require('connect-route');
var connect_st = require('st');
var connect_rate_limit = require('connect-ratelimit');
var DocumentHandler = require('./lib/document_handler'); var DocumentHandler = require('./lib/document_handler');
@ -99,42 +102,61 @@ var documentHandler = new DocumentHandler({
keyGenerator: keyGenerator keyGenerator: keyGenerator
}); });
// Set the server up with a static cache var app = connect();
connect.createServer(
// First look for api calls // Rate limit all requests
connect.router(function(app) { if (config.rateLimits) {
// get raw documents - support getting with extension config.rateLimits.end = true;
app.get('/raw/:id', function(request, response, next) { app.use(connect_rate_limit(config.rateLimits));
var skipExpire = !!config.documents[request.params.id]; }
var key = request.params.id.split('.')[0];
return documentHandler.handleRawGet(key, response, skipExpire); // first look at API calls
}); app.use(route(function(router) {
// add documents // get raw documents - support getting with extension
app.post('/documents', function(request, response, next) { router.get('/raw/:id', function(request, response, next) {
return documentHandler.handlePost(request, response); var skipExpire = !!config.documents[request.params.id];
}); var key = request.params.id.split('.')[0];
// get documents return documentHandler.handleRawGet(key, response, skipExpire);
app.get('/documents/:id', function(request, response, next) { });
var skipExpire = !!config.documents[request.params.id]; // add documents
return documentHandler.handleGet( router.post('/documents', function(request, response, next) {
request.params.id, return documentHandler.handlePost(request, response);
response, });
skipExpire // get documents
); router.get('/documents/:id', function(request, response, next) {
}); var skipExpire = !!config.documents[request.params.id];
}), return documentHandler.handleGet(
// Otherwise, static request.params.id,
connect.staticCache(), response,
connect.static(__dirname + '/static', { maxAge: config.staticMaxAge }), skipExpire
// Then we can loop back - and everything else should be a token, );
// so route it back to /index.html });
connect.router(function(app) { }));
app.get('/:id', function(request, response, next) {
request.url = request.originalUrl = '/index.html'; // Otherwise, try to match static files
next(); app.use(connect_st({
}); path: __dirname + '/static',
}), content: { maxAge: config.staticMaxAge },
connect.static(__dirname + '/static', { maxAge: config.staticMaxAge }) passthrough: true,
).listen(config.port, config.host); index: false
}));
// Then we can loop back - and everything else should be a token,
// so route it back to /
app.use(route(function(router) {
router.get('/:id', function(request, response, next) {
request.sturl = '/';
next();
});
}));
// And match index
app.use(connect_st({
path: __dirname + '/static',
content: { maxAge: config.staticMaxAge },
index: 'index.html'
}));
http.createServer(app).listen(config.port, config.host);
winston.info('listening on ' + config.host + ':' + config.port); winston.info('listening on ' + config.host + ':' + config.port);