Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Route options #34

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open

Route options #34

wants to merge 4 commits into from

Conversation

yonjah
Copy link

@yonjah yonjah commented Aug 15, 2017

This pull request will allow to override settings for each route.
I also added a few useful settings to override -
enabled - to enable rate limiting only for specific routes
addHeaders - to add rate liming headers to response
count - to change the cost of a route

All new settings are optional and default to original behavior.

@dschenkelman
Copy link
Owner

@yonjah thanks for the PR. I'm a bit backed up at work but will try to make some time to review

README.md Outdated
@@ -44,11 +44,94 @@ The object has the following schema (validated [here](./lib/index.js) using [Joi
* `done: (err: Error, key: String)` - A function that takes an error as the first parameter and the bucket key as the second parameter.

**Optional**
* `enabled: Boolean default(true)` - if `true` rate limiting will be enabled you can set it to `false` on route settings to disable rate limiting
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure enabled is the best way of describing this. e.g.: enabled: false at the top level can be confusing.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"can set it to false on route settings to disable rate limiting"

Why "on route settings"? If it is done at the global level this is also disabled. What about "if true rate limiting will be enabled. Setting this false` disable this at the appropriate level (route or global)"?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree "enabled" can be confusing but couldn't think of a better term.
I'll change the description as you suggested

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what if we call it allRoutes and it can only be set at the global plug in level not at the route level? if a route has the plugin defined, it wants to enable it so no need for the flag at the route level

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That sounds good for my use case where I have many routes which are not rate limited and I only want to enable it for a few routes.
But if you want to enable it for most route and only disable it on a few routes it will be more cumbersome

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm, I see. let's, leave as is

README.md Outdated
@@ -44,11 +44,94 @@ The object has the following schema (validated [here](./lib/index.js) using [Joi
* `done: (err: Error, key: String)` - A function that takes an error as the first parameter and the bucket key as the second parameter.

**Optional**
* `enabled: Boolean default(true)` - if `true` rate limiting will be enabled you can set it to `false` on route settings to disable rate limiting
* `addHeaders: Boolean default(true)` - if `true` rate limiting headers will be sent with response
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this should be an option. This should always be true. Can you expand on why you think it should be optional?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My main use case for using rate limiting is to disable brute force on login attempts and tokens.
Since I don't see a case where legitimate use will hit those limits and if he does all he need to know is to try again in a few minutes. I don't want to give attacker extra information about when exactly he can do each attempt.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, sounds good. what about sendResponseHeaders?

README.md Outdated
@@ -44,11 +44,94 @@ The object has the following schema (validated [here](./lib/index.js) using [Joi
* `done: (err: Error, key: String)` - A function that takes an error as the first parameter and the bucket key as the second parameter.

**Optional**
* `enabled: Boolean default(true)` - if `true` rate limiting will be enabled you can set it to `false` on route settings to disable rate limiting
* `addHeaders: Boolean default(true)` - if `true` rate limiting headers will be sent with response
* `count: Number default(1)` - how many tokens request should cost useful when you want one route to be more expensive than another but use the same bucket
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you share a bit more about this use case? I understand the concept, but this is not something that I see being very common

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just thought it might be useful as a route option.
Personally I don't have a use case for it

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's drop it for the time being then please. it adds additional logic with no usage

README.md Outdated
* `onError: (error, reply) => ()` - A function that takes the `error` that occurred when trying to get a token from the bucket and the `reply` interface.
* `error: Error` - The error that occurred.
* `reply: Reply` - The hapi.js [reply interface](http://hapijs.com/api#reply-interface).
> If an error occurs and no function is provided, the request lifecycle continues normally as if there was no token bucket restriction. This is a useful default behavior in case the limitd server goes down.

Options can be overridden in route settings.
if plugin is disabled by default setting patova setting for route will also enable the plugin for the route.
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure about what this particular line means. Can you provide a bit more detail please?

README.md Outdated
* `onError: (error, reply) => ()` - A function that takes the `error` that occurred when trying to get a token from the bucket and the `reply` interface.
* `error: Error` - The error that occurred.
* `reply: Reply` - The hapi.js [reply interface](http://hapijs.com/api#reply-interface).
> If an error occurs and no function is provided, the request lifecycle continues normally as if there was no token bucket restriction. This is a useful default behavior in case the limitd server goes down.

Options can be overridden in route settings.
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would move from here until "Contributing" to a wiki article, leaving the README.md simpler.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you want me to remove this completely or create a wiki page and add a link ?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's remove it. it is simple enough

lib/index.js Outdated
const extractKeyAndTakeToken = function(options, request, reply, type) {
options.extractKey(request, reply, (err, key) =>{
const limitd = options.limitd;
const count = options.count;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's discuss usage above, but I would probably remove from now

if (onError) { return onError(err, reply); }
// by default we don't fail if limitd is unavailable
return reply.continue();
}

const oldMinimumLimitResponse = request.plugins.patova && request.plugins.patova.limit
const newMinimumLimitResponse = getMinimumLimit(currentLimitResponse, oldMinimumLimitResponse)
const oldMinimumLimitResponse = request.plugins.patova && request.plugins.patova.limit;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks

lib/index.js Outdated
newMinimumLimitResponse.limit,
newMinimumLimitResponse.remaining,
newMinimumLimitResponse.reset);
if (options.addHeaders) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As mentioned previously, I would not make this optional unless there is a good reason to

lib/index.js Outdated
reply.continue();
});

function parseRouteOptions(request) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this logic looks good. it is not really parsing though, right? I would change the function name to getRouteOptions maybe?

lib/index.js Outdated
}

exports.register = function (server, options, next) {
Joi.validate(options, schema, { abortEarly: false }, (err, processedOptions) => {
const defaults = {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lib/index.js Outdated
const extractKeyAndTakeToken = function(options, request, reply, type) {
options.extractKey(request, reply, (err, key) =>{
const limitd = options.limitd;
const count = options.count;
if (err) { return reply(err); }

if (!limitd) {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BTW I don't think limitd can be missing or falsey at this stage so this can probably be removed

@yonjah
Copy link
Author

yonjah commented Aug 18, 2017

Ok hope it looks better now

extractKey(request, reply, (err, key) =>{
const extractKeyAndTakeToken = function(options, request, reply, type) {
options.extractKey(request, reply, (err, key) =>{
const limitd = options.limitd;
if (err) { return reply(err); }

if (!limitd) {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dschenkelman do you want me to also remove this check ?
I'm not sure why it's there but I don't think limitd can ever be falsey at this stage

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no, this is fine

lib/index.js Outdated
if (routeOptions === undefined) {
return pluginOptions;
}
if (routeOptions._merged) { //already merged with previous pluginOptions;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe this is a premature optimization? I think hapi merges per request. Storing _merged on the plugins.patova object which we don't own feels odd.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea sure. It just feels a bit wasteful since it can be deduced in advance.
But this is anyway kinda hacky so I don't mind removing it

@@ -44,11 +44,14 @@ The object has the following schema (validated [here](./lib/index.js) using [Joi
* `done: (err: Error, key: String)` - A function that takes an error as the first parameter and the bucket key as the second parameter.

**Optional**
* `enabled: Boolean default(true)` - if true rate limiting will be enabled for all routes. Setting this `false` will only rate limit routes which have the plugin defined
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've been thinking a bit more and we can probably change this to allRoutes as you suggested.
if it's set to true a user can still disable a specific route by setting the route settings to false instead of an object

config: {
    plugins: {
      patova: false
    }
}

So we can accommodate both use cases this way.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants