ratelimiter

package module
v1.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 4, 2018 License: Apache-2.0 Imports: 8 Imported by: 1

README

Go Rate Limiter

GoDoc Travis Coveralls github Report Card

ratelimiter is a multi-ratelimiter for go. It is easily configurable, allows whitelist, and easy to use.

Rate Limiters

type Limiter interface {
        Limit(string) bool
}

You create a limiter by providing it with a configured Limit which is either manually created or parsed from a string

// Using a parsed limit
rl := ratelimiter.MustParseLimit("10/1m")
limiter := ratelimiter.NewRedisLimiter(redisPool, rls)

// Manually created limit
// one per minute, non-global (IP specific)
limit := ratelimiter.Limit{
        Global: false,
        Limit: 1,
        Dur: time.Minute
}
limiter := ratelimiter.NewRedisLimiter(redisPool, limit)

Limits

Limits are defined as the following struct

type Limit struct {
	Global bool
	Limit  int
	Dur    time.Duration
}

You can either manually create them or you can use the parser. The parser parses strings separated into three sections

  • Section 1: How many requests to limit to
  • Section 2: For what duration
  • Section 3: (optional) is this limit global?
Example limit strings
// create a Limit which limits requests to 1 per second by identifier (IP address)
rl := ratelimiter.MustParseLimit("1/1s")

// create a Limit which limits requests to 10 per 5 minutes by identifier (IP address)
rl := ratelimiter.MustParseLimit("10/5m")

// create a Limit which limits requests to 1000 per day globally
rl := ratelimiter.MustParseLimit("1000/24h/g")

// create chained Limits
rls := ratelimiter.MustParseLimits([]string{"1000/24h/g", "1/1s", "10/1m"})

Ratelimits are executed in descending order of duration. If you configure the following two limits:

  1. 1/1s
  2. 10/1h

They will be executed in reverse order because the larger groups should be checked first. Global rate limits are also executed first.

Whitelist

To whitelist IP addresses use the WhitelistedLimiter which wraps a real limiter

rl := ratelimiter.MustParseLimit("10/1m")
limiter := ratelimiter.NewRedisLimiter(redisPool, rls)

whitelist := []string{"127.0.0.1"}
wl := ratelimiter.NewWhitelistedLimiter(limiter, whitelist)

Implemented Limiters

For now only RedisRatelimiter is implemented, however more can be added. Feel free to submit a PR.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrMalformedLimit is used after attempting to Parse a malformed limit string
	ErrMalformedLimit = errors.New("malformed string")

	// ErrMalformedLimitNumber is used when the first number (the limit) is not a number
	ErrMalformedLimitNumber = errors.New("malformed limit")

	// ErrInvalidLimitNumber is used when the first number (the limit) is < 0
	ErrInvalidLimitNumber = errors.New("limit must be > 0")

	// ErrInvalidDuration is used when the duration is < 0s
	ErrInvalidDuration = errors.New("duration must be > 0s")
)

Functions

func Middleware

func Middleware(l Limiter) func(http.Handler) http.Handler

Middleware creates a new rate limiter for HTTP

Types

type Limit

type Limit struct {
	Global bool
	Limit  int
	Dur    time.Duration
}

Limit is a limiter used with New to execuate a ratelimiter

func MustParseLimit

func MustParseLimit(limit string) Limit

MustParseLimit calls ParseLimit and panics if there is an error

func MustParseLimits

func MustParseLimits(limits []string) []Limit

MustParseLimits parses limits and then panics if there is an error

func ParseLimit

func ParseLimit(limit string) (Limit, error)

ParseLimit parses a limiter string limit should be in the format of <count>/<duration>/g where count is the maximum count of requests, duration is the length of time, and /g means that the limiter is global and not ip specific

Example:

1/1m    = one request per minute per IP address
10/24h/g = ten requests per day globally

func ParseLimits

func ParseLimits(limits []string) ([]Limit, error)

ParseLimits parses a slice of limits with ParseLimit

func (*Limit) String

func (l *Limit) String() string

type Limiter

type Limiter interface {
	Limit(ip string) bool
}

Limiter checks an ip address to see if it should be ratelimited

type NopLimiter

type NopLimiter struct{}

NopLimiter is a limiter that returns false for all Limit() queries

func (*NopLimiter) Limit

func (l *NopLimiter) Limit(ip string) bool

Limit always returns false

type RedisLimiter

type RedisLimiter struct {
	Pool         redisPool
	Limits       []Limit
	LimitOnError bool
	OnError      func(ip string, err error)
}

RedisLimiter is a rate limit which can evaluate an IP address to determine if it should be rate limited using Redis as a backend

func NewRedisLimiter

func NewRedisLimiter(pool redisPool, limits []Limit) *RedisLimiter

NewRedisLimiter creates a properly initialized RedisLimiter

func (*RedisLimiter) Limit

func (l *RedisLimiter) Limit(ip string) bool

Limit checks an IP address to see if it should be ratelimited. It returns true if the IP address should be ratelimited and false otherwise any errors encountered will return *RedisLimiter.LimitOnError plus the error

type WhitelistedLimiter

type WhitelistedLimiter struct {
	Limiter     Limiter
	Whitelist   []string
	OnWhitelist func(ip string)
}

WhitelistedLimiter wraps a ratelimiter with a whitelist

func NewWhitelistedLimiter

func NewWhitelistedLimiter(limiter Limiter, whitelist []string) *WhitelistedLimiter

NewWhitelistedLimiter constructs a new WhitelistedLimiter

func (*WhitelistedLimiter) Limit

func (w *WhitelistedLimiter) Limit(ip string) bool

Limit checks the whitelist for whitelisted IP addresses and then return false if any match. If none match then it defers to w.Limiter.Limit

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL