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,22 +102,28 @@ 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) {
config.rateLimits.end = true;
app.use(connect_rate_limit(config.rateLimits));
}
// first look at API calls
app.use(route(function(router) {
// get raw documents - support getting with extension // get raw documents - support getting with extension
app.get('/raw/:id', function(request, response, next) { router.get('/raw/:id', function(request, response, next) {
var skipExpire = !!config.documents[request.params.id]; var skipExpire = !!config.documents[request.params.id];
var key = request.params.id.split('.')[0]; var key = request.params.id.split('.')[0];
return documentHandler.handleRawGet(key, response, skipExpire); return documentHandler.handleRawGet(key, response, skipExpire);
}); });
// add documents // add documents
app.post('/documents', function(request, response, next) { router.post('/documents', function(request, response, next) {
return documentHandler.handlePost(request, response); return documentHandler.handlePost(request, response);
}); });
// get documents // get documents
app.get('/documents/:id', function(request, response, next) { router.get('/documents/:id', function(request, response, next) {
var skipExpire = !!config.documents[request.params.id]; var skipExpire = !!config.documents[request.params.id];
return documentHandler.handleGet( return documentHandler.handleGet(
request.params.id, request.params.id,
@ -122,19 +131,32 @@ connect.createServer(
skipExpire skipExpire
); );
}); });
}), }));
// Otherwise, static
connect.staticCache(), // Otherwise, try to match static files
connect.static(__dirname + '/static', { maxAge: config.staticMaxAge }), app.use(connect_st({
path: __dirname + '/static',
content: { maxAge: config.staticMaxAge },
passthrough: true,
index: false
}));
// Then we can loop back - and everything else should be a token, // Then we can loop back - and everything else should be a token,
// so route it back to /index.html // so route it back to /
connect.router(function(app) { app.use(route(function(router) {
app.get('/:id', function(request, response, next) { router.get('/:id', function(request, response, next) {
request.url = request.originalUrl = '/index.html'; request.sturl = '/';
next(); next();
}); });
}), }));
connect.static(__dirname + '/static', { maxAge: config.staticMaxAge })
).listen(config.port, config.host); // 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);