Skip to content

Commit 8862b37

Browse files
author
Donald Gray
committed
Updated readme. Fixed commented out code that shouldn't have been pushed
1 parent ad12fba commit 8862b37

File tree

3 files changed

+39
-24
lines changed

3 files changed

+39
-24
lines changed

readme.md

Lines changed: 36 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ A rate limiting plugin for [ServiceStack](https://servicestack.net/) that uses [
88

99
An accessible running Redis instance.
1010

11-
The plugin needs to be passed an IRedisClientsManager instance to work.
11+
The plugin needs to be passed an `IRedisClientsManager` instance to work.
1212

1313
## Quick Start
1414

@@ -32,11 +32,11 @@ public override void Configure(Container container)
3232

3333
There is a baked-in default limit for each DTO type of: 10 requests per minute, 30 request per hour.
3434

35-
To override this add an AppSetting with key *lmt:default* to the App.Config/Web.Config of project running AppHost will provide limit values.
35+
To override this add an AppSetting with key *ss/lmt/default* to the App.Config/Web.Config of project running AppHost will provide limit values.
3636

3737
```
3838
<!-- default of 10 per second, 50 per minute, 200 per hour-->
39-
<add key="lmt:default" value="{Limits:[{Limit:10,Seconds:1},{Limit:50,Seconds:60},{Limit:200,Seconds:3600}]}"/>
39+
<add key="ss/lmt/default" value="{Limits:[{Limit:10,Seconds:1},{Limit:50,Seconds:60},{Limit:200,Seconds:3600}]}"/>
4040
```
4141

4242
The lookup keys for more granular control are specified below.
@@ -53,46 +53,61 @@ The "Postman Samples" folder contains a sample [Postman](https://www.getpostman.
5353
## Overview
5454
The plugin registers a [global request filter](https://github.com/ServiceStack/ServiceStack/wiki/Request-and-response-filters#global-request-filters). Every time a request is received a check is made using a [Redis LUA script](http://redis.io/commands/eval). If the specified limits have not been hit then the request is processed as expected. However, if the limit has been reached then a [429](https://tools.ietf.org/html/rfc6585#page-3) "Too Many Requests" response is generated and processing of the request is halted.
5555

56-
Two possible headers are returned from any endpoint that is protecte: x-ratelimit-request and x-ratelimit-user. They will show the seconds duration, the limit and how many remaining calls are available per request, or user respectively.
56+
Two possible headers are returned from any endpoint that is protected: `x-ratelimit-request` and `x-ratelimit-user`. They will show the seconds duration, the limit and how many remaining calls are available per request, or user respectively.
5757

5858
### Rate Limits
5959

6060
At a high level, rate limits can be set at either **User** or **Resource** level (by default a resource in this instance is the DTO type name). Limits are fetched from [IAppSettings](https://github.com/ServiceStack/ServiceStack/wiki/AppSettings) and can be set at the following levels, in order of precedence:
6161

62-
* User for resource - User 123 can make X requests to a specific resource (e.g. /api/products). (config key: "lmt:{resourceName}:{userId}")
63-
* User - User 123 can make X total requests for specific time period(s). (config key: "lmt:usr:{userId}")
64-
* User fallback - Fallback total request limit for users without specific defaults. (config key: "lmt:usr:default")
65-
* Resource - Each user can make X requests to a resource (e.g. /api/products) for specific time period(s). (config key: "lmt:{resourceName}".)
66-
* Resource fallback - Fallback limit for requests individual users can make to a resource. (config key: "lmt:default")
62+
| Order | Type | Description | Default Key |
63+
| --- | --- | --- | --- |
64+
| 1 | User for resource | User 123 can make X requests to a specific resource (e.g. /api/products) | `ss/lmt/{resourceName}/{userId}` |
65+
| 2 | User | User 123 can make X total requests for specific time period(s) | `ss/lmt/usr/{userId}` |
66+
| 3 | User fallback | Fallback total request limit for users without specific defaults | `ss/lmt/usr/default` |
67+
| 4 | Resource | Each user can make X requests to a resource (e.g. /api/products) for specific time period(s) | `ss/lmt/{resourceName}` |
68+
| 5 | Resource fallback | Fallback limit for requests individual users can make to a resource. | `ss/lmt/default` |
6769

6870
User limits AND resource limits will be calculated at the same time (if present). User limits are calculated first. If a limit is hit subsequent wider limits are not incremented (e.g. if limit per second is hit, limit per minute would not be counted).
6971

72+
#### Customising Keys
73+
74+
It is possible to change both the prefix, default *ss* (to distinguish ServiceStack settings), and delimiter, default */*, as static variables of the `LimitKeyGenerator` class. For example:
75+
76+
```csharp
77+
LimitKeyGenerator.Delimiter = "-";
78+
LimitKeyGenerator.Prefix = null;
79+
```
80+
81+
Would produce keys like `lmt-default` rather than `ss/lmt/default`.
82+
7083
#### Limit Representation
7184
All limits are per second and are stored as a LimitGroup object serialised to JSV. For example, the following shows a limit of 5 requests per second, 15 per minute (60s) and 100 per hour (3600s):
72-
```xml
85+
```json
7386
{Limits:[{Limit:5,Seconds:1},{Limit:15,Seconds:60},{Limit:100,Seconds:3600}]}
7487
```
7588

7689
#### LUA Script
7790
A LUA script is used for doing the heavy lifting and keeping track of limit totals. To save bandwith on calls to Redis the [EVALSHA](http://redis.io/commands/evalsha) command is used to call a LUA script which has previously been [loaded](http://redis.io/commands/script-load).
7891

79-
The default implementation of ILimitProvider (see below) will check IAppSettings for a value with key "script:ratelimit". This value will be the SHA1 of the script to use. Using this method means that the script can be managed external to the plugin.
92+
The default implementation of ILimitProvider (see below) will check IAppSettings for a value with key *ss/script/ratelimit*. This value will be the SHA1 of the script to use. Using this method means that the script can be managed external to the plugin.
8093

8194
If an AppSetting is not found with the specified key then the RateLimitHash.lua script is loaded, the SHA1 is stored and used for subsequent requests.
8295

8396
**Note:** The RateLimitHash.lua script does not currently use a sliding expiry, instead is resets every X seconds. E.g. if the limit is for 50 requests in 3600 seconds (1 hour) then 50 requests could be made at 10:59 and then 50 request can be made at 11:01. This is something that may be looked at in the future.
8497

8598
### Extensibility
86-
There are a few extension point that can be set when adding the plugin:
87-
88-
* CorrelationIdExtractor - This is a delegate function that customises how an individual request is identified. By default it uses the value of HTTP Header with name specified by CorrelationIdHeader property. **Note:** This is primarily required for when a ServiceStack service calls subsequent ServiceStack services that all use this plugin as it will avoid user totals being incremented multiple times for the same request.
89-
* CorrelationIdHeader - The name of the header used for extracting correlation Id from request (if using default method). Default: x-mac-requestid.
90-
* StatusDescription - the status description returned when limit is breached. Default "Too many requests".
91-
* LimitStatusCode - the status code returned when limit is breached. Default 429.
92-
* KeyGenerator - an implementation of IKeyGenerator for generating config lookup key(s) for request. Defaults outlined above.
93-
* LimitProvider - an implementation of ILimitProvider for getting RateLimits for current request. Default uses IKeyGenerator keys to lookup IAppSettings.
94-
95-
These are all properties of the RateLimitFeature class and can be set when instantiating the plugin
99+
There are a few extension point that can be set when adding the plugin. These are all properties of the RateLimitFeature class and can be set when instantiating the plugin:
100+
101+
| Property | Description | Notes |
102+
| --- | --- | --- |
103+
| CorrelationIdExtractor | This is a delegate function that customises how an individual request is identified. | By default it uses the value of HTTP Header with name specified by CorrelationIdHeader property. This is primarily required for when a ServiceStack service calls subsequent ServiceStack services that all use this plugin as it will avoid user totals being incremented multiple times for the same request. |
104+
| CorrelationIdHeader | The name of the header used for extracting correlation Id from request (if using default method) | Default: `x-mac-requestid` |
105+
| StatusDescription | The status description returned when limit is breached | Default: "Too many requests" |
106+
| LimitStatusCode | the status code returned when limit is breached. | Default: 429 |
107+
| KeyGenerator | an implementation of IKeyGenerator for generating config lookup key(s) for request. | Defaults outlined above |
108+
| LimitProvider | an implementation of ILimitProvider for getting RateLimits for current request. | Default uses `IKeyGenerator` keys to lookup `IAppSettings` |
109+
110+
Example:
96111
```csharp
97112
Plugins.Add(new RateLimitFeature(Container.Resolve<IRedisClientsManager>())
98113
{

test/DemoService/AppHost.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,11 @@ public override void Configure(Container container)
3737

3838
private void SetupPlugins()
3939
{
40-
/*Plugins.Add(new AuthFeature(() => new AuthUserSession(),
40+
Plugins.Add(new AuthFeature(() => new AuthUserSession(),
4141
new IAuthProvider[]
4242
{
4343
new BasicAuthProvider()
44-
}));*/
44+
}));
4545

4646
/*LimitKeyGenerator.Delimiter = ":";
4747
LimitKeyGenerator.Prefix = null;*/

test/DemoService/Program.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public class DemoService : Service
2626
public object Any(DemoRequest demoRequest) => new DemoResponse { Message = "Response from Demo Service" };
2727
}
2828

29-
//[Authenticate]
29+
[Authenticate]
3030
public class DemoRequest : IReturn<DemoResponse>
3131
{
3232
}

0 commit comments

Comments
 (0)