Skip to content

Rate-limiting for WAI applications based on the leaky bucket algorithm

License

Notifications You must be signed in to change notification settings

channable/wai-middleware-rate-limit

Repository files navigation

WAI Rate-limiting Middleware

Easily add rate-limiting to your WAI applications based on the leaky bucket algorithm.

This library allows you to rate-limit incoming HTTP requests based on

  • the IP address of the client
  • the authentication token of the client (currently tied to Web.JWT-style tokens)

If a request with an authentication token comes in, the token rate-limits will be applied. If an unauthenticated request comes in the IP rate-limiting will be applied.

Usage

There is a minimal, self-contained example in example/Main.hs that shows how to rate-limit on IP. You have to define LeakyBucketSpec which specifies the capacity of the bucket, and the leak rate. E.g. a LeakyBucketSpec 10 (fromHz 1) would be a bucket with a capacity of 10 requests, and a leak rate of 1 request per second. A client could thus send 10 requests in a burst, and subsequently one request per second without getting rate-limited. When sending more requests than that we return a "429 Too Many Requests" status code.

Minimal usage example:

main :: IO ()
main = do
    -- set the bucket size to 1 and the leak rate to 1 Hz, i.e. 1 request per second is allowed
    let authClaimLeakyBucketSpec = LeakyBucketSpec 1 (fromHz 1)
        ipLeakyBucketSpec = LeakyBucketSpec 1 (fromHz 1)

    -- initialize the in-memory rate limiting state
    rateLimitState <- initRateLimitState authClaimLeakyBucketSpec ipLeakyBucketSpec

    let
        -- this is the actual rate-limiting middleware. We pass 'Nothing' here to keep this
        -- example simple. In a real application, that has authenticated users, we would pass
        -- the concrete token type here.
        middleware = rateLimitMiddleware rateLimitState (Nothing :: Maybe (Int, Int))
        app = logStdoutDev $ middleware $ staticApp $ defaultWebAppSettings "."

    -- Start a web server, serving static files from the local directory.
    -- Requests are rate-limited based on IP address, according to the "ipLeakyBucketSpec" above.
    -- You can test this by sending a few requests with "curl localhost:8080" and noticing the
    -- "429 Too Many Requests" responses, that are being logged to stdout.
    run 8080 app

Implementation

This library implements the leaky bucket algorithm. Internally, we use an STMMap from stm-containers to keep track of the rate-limiting state. There is one STMMap to keep track of IP-based state, and another STMMap to keep track of token-based state.

Limitations

The library currently only supports in-memory storage of the rate-limiting state. A restart of the server process, will thus lose all rate-limiting state.

Another limitation is that only Web.JWT-style authentication tokens are supported, instead of arbitrary token types.

Building

The library can be built with stack build.

The example application can be run with: stack run wai-middleware-rate-limit-example

About

Rate-limiting for WAI applications based on the leaky bucket algorithm

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published