ratelimit

package
v0.0.0-...-202847b Latest Latest
Warning

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

Go to latest
Published: Jan 1, 2023 License: Apache-2.0 Imports: 20 Imported by: 3

Documentation

Overview

Package ratelimit implements scope based HTTP rate limiting.

Sub-package `backendratelimit` implements the external configuration loading. Sub-package `memstore` and `redigostore` provides rate limiting algorithms and their storage possibilities. Both packages should be used as either functional options to a ratelimit service or as functional option factories to the backend type.

Index

Constants

This section is empty.

Variables

DefaultDeniedHandler defines the service wide denied handler.

Functions

This section is empty.

Types

type Option

type Option func(*Service) error

Option can be used as an argument in NewService to configure it with different settings.

func OptionsError

func OptionsError(err error) []Option

OptionsError helper function to be used within the backend package or other sub-packages whose functions may return an OptionFactoryFunc.

func WithDebugLog

func WithDebugLog(w io.Writer) Option

WithDebugLog creates a new standard library based logger with debug mode enabled. The passed writer must be thread safe.

func WithDefaultConfig

func WithDefaultConfig(id scope.TypeID) Option

WithDefaultConfig applies the default ratelimit configuration settings based for a specific scope. This function overwrites any previous set options.

Default values are:

  • Denied Handler: http.Error(w, http.StatusText(http.StatusTooManyRequests), http.StatusTooManyRequests)
  • VaryByer: returns an empty key

Example:

s := MustNewService(WithDefaultConfig(scope.Store,1), WithVaryBy(scope.Store, 1, myVB))

func WithDeniedHandler

func WithDeniedHandler(next http.Handler, scopeIDs ...scope.TypeID) Option

WithDeniedHandler sets a custom denied handler for a specific scope. The default denied handler returns a simple:

http.Error(w, http.StatusText(http.StatusTooManyRequests), http.StatusTooManyRequests)

func WithDisable

func WithDisable(isDisabled bool, scopeIDs ...scope.TypeID) Option

WithDisable disables the current service and calls the next HTTP handler.

The variadic "scopeIDs" argument define to which scope the value gets applied and from which parent scope should be inherited. Setting no "scopeIDs" sets the value to the default scope. Setting one scope.TypeID defines the primary scope to which the value will be applied. Subsequent scope.TypeID are defining the fall back parent scopes to inherit the default or previously applied configuration from.

func WithErrorHandler

func WithErrorHandler(eh mw.ErrorHandler, scopeIDs ...scope.TypeID) Option

WithErrorHandler adds a custom error handler. Gets called in the http.Handler after the scope can be extracted from the context.Context and the configuration has been found and is valid. The default error handler prints the error to the user and returns a http.StatusServiceUnavailable.

The variadic "scopeIDs" argument define to which scope the value gets applied and from which parent scope should be inherited. Setting no "scopeIDs" sets the value to the default scope. Setting one scope.TypeID defines the primary scope to which the value will be applied. Subsequent scope.TypeID are defining the fall back parent scopes to inherit the default or previously applied configuration from.

func WithGCRAStore

func WithGCRAStore(store throttled.GCRAStore, duration rune, requests, burst int, scopeIDs ...scope.TypeID) Option

WithGCRAStore creates a new GCRA rate limiter with a custom storage backend. Duration: (s second,i minute,h hour,d day) GCRA => https://en.wikipedia.org/wiki/Generic_cell_rate_algorithm

func WithLogger

func WithLogger(l log.Logger) Option

WithLogger convenient helper function to apply a logger to the Service type.

func WithMarkPartiallyApplied

func WithMarkPartiallyApplied(partially bool, scopeIDs ...scope.TypeID) Option

WithMarkPartiallyApplied if set to true marks a configuration for a scope as partially applied with functional options set via source code. The internal service knows that it must trigger additionally the OptionFactoryFunc to load configuration from a backend. Useful in the case where parts of the configurations are coming from backend storages and other parts like http handler have been set via code. This function should only be applied in case you work with WithOptionFactory().

The variadic "scopeIDs" argument define to which scope the value gets applied and from which parent scope should be inherited. Setting no "scopeIDs" sets the value to the default scope. Setting one scope.TypeID defines the primary scope to which the value will be applied. Subsequent scope.TypeID are defining the fall back parent scopes to inherit the default or previously applied configuration from.

func WithOptionFactory

func WithOptionFactory(f OptionFactoryFunc) Option

WithOptionFactory applies a function which lazily loads the options from a slow backend (config.Getter) depending on the incoming scope within a request. For example applies the backend configuration to the service.

Once this option function has been set all other manually set option functions, which accept a scope and a scope ID as an argument, will NOT be overwritten by the new values retrieved from the configuration service.

cfgStruct, err := backendratelimit.NewConfigStructure()
if err != nil {
	panic(err)
}
be := backendratelimit.New(cfgStruct)

srv := ratelimit.MustNewService(
	ratelimit.WithOptionFactory(be.PrepareOptions()),
)

func WithRateLimiter

func WithRateLimiter(rl throttled.RateLimiter, scopeIDs ...scope.TypeID) Option

WithRateLimiter creates a rate limiter for a specific scope with its ID. The rate limiter is already warmed up.

func WithRootConfig

func WithRootConfig(cg config.Getter) Option

WithRootConfig sets the root configuration service to retrieve the scoped base configuration. If you set the option WithOptionFactory() then the option WithRootConfig() does not need to be set as it won't get used.

func WithServiceErrorHandler

func WithServiceErrorHandler(eh mw.ErrorHandler) Option

WithServiceErrorHandler sets the error handler on the Service object. Convenient helper function.

func WithVaryBy

func WithVaryBy(vb VaryByer, scopeIDs ...scope.TypeID) Option

WithVaryBy allows to set a custom key producer. VaryByer is called for each request to generate a key for the limiter. If it is nil, the middleware panics. The default VaryByer returns an empty string so that all requests uses the same key. VaryByer must be thread safe.

type OptionFactories

type OptionFactories struct {
	// contains filtered or unexported fields
}

OptionFactories allows to register multiple OptionFactoryFunc identified by their names. Those OptionFactoryFuncs will be loaded in the backend package depending on the configured name under a certain path. This type is embedded in the backendratelimit.Configuration type.

func NewOptionFactories

func NewOptionFactories() *OptionFactories

NewOptionFactories creates a new struct and initializes the internal map for the registration of different option factories.

func (*OptionFactories) Deregister

func (of *OptionFactories) Deregister(name string)

Deregister removes a functional option factory from the internal register.

func (*OptionFactories) Lookup

func (of *OptionFactories) Lookup(name string) (OptionFactoryFunc, error)

Lookup returns a functional option factory identified by name or an error if the entry doesn't exists. May return a NotFound error behaviour.

func (*OptionFactories) Names

func (of *OptionFactories) Names() []string

Names returns an unordered list of names of all registered functional option factories.

func (*OptionFactories) Register

func (of *OptionFactories) Register(name string, factory OptionFactoryFunc)

Register adds another functional option factory to the internal register. Overwrites existing entries.

type OptionFactoryFunc

type OptionFactoryFunc func(config.Scoped) []Option

OptionFactoryFunc a closure around a scoped configuration to figure out which options should be returned depending on the scope brought to you during a request.

type ScopedConfig

type ScopedConfig struct {

	// DeniedHandler can be customized instead of showing a HTTP status 429
	// error page once the HTTPRateLimit has been reached.
	// It will be called if the request gets over the limit.
	DeniedHandler http.Handler
	// RateLimiter default not set. It gets set either through the developer
	// calling WithRateLimiter() or via OptionFactoryFunc.
	throttled.RateLimiter
	// VaryByer is called for each request to generate a key for the limiter. If
	// it is nil, the middleware panics. The default VaryByer returns an empty
	// string so that all requests uses the same key.
	VaryByer
	// contains filtered or unexported fields
}

ScopedConfig scoped based configuration and should not be embedded into your own types. Call ScopedConfig.ScopeHash to know to which scope this configuration has been bound to.

type Service

type Service struct {
	// contains filtered or unexported fields
}

Service creates a middleware that facilitates using a Limiter to limit HTTP requests.

func MustNew

func MustNew(opts ...Option) *Service

MustNew same as New() but panics on error. Use only during app start up process.

func New

func New(opts ...Option) (*Service, error)

New creates a new rate limit middleware.

Default DeniedHandler returns http.StatusTooManyRequests.

Default RateLimiterFactory is the NewGCRAMemStore(). If *PkgBackend has been provided the values from the configration will be taken otherwise GCRAMemStore() uses the Default* variables.

func (*Service) ClearCache

func (s *Service) ClearCache() error

ClearCache clears the internal map storing all scoped configurations. You must reapply all functional options. TODO(CyS) all previously applied options will be automatically reapplied.

func (*Service) ConfigByScope

func (s *Service) ConfigByScope(websiteID, storeID int64) (ScopedConfig, error)

ConfigByScope creates a new scoped configuration depending on the Service.useWebsite flag. If useWebsite==true the scoped configuration contains only the website->default scope despite setting a store scope. If an OptionFactory is set the configuration gets loaded from the backend. A nil root config causes a panic.

func (*Service) ConfigByScopeID

func (s *Service) ConfigByScopeID(current scope.TypeID, parent scope.TypeID) (scpCfg ScopedConfig, _ error)

ConfigByScopeID returns the correct configuration for a scope and may fall back to the next higher scope: store -> website -> default. If `current` TypeID is Store, then the `parent` can only be Website or Default. If an entry for a scope cannot be found the next higher scope gets looked up and the pointer of the next higher scope gets assigned to the current scope. This prevents redundant configurations and enables us to change one scope configuration with an impact on all other scopes which depend on the parent scope. A zero `parent` triggers no further look ups. This function does not load any configuration (config.Getter related) from the backend and accesses the internal map of the Service directly.

Important: a "current" scope cannot have multiple "parent" scopes.

func (*Service) ConfigByScopedGetter

func (s *Service) ConfigByScopedGetter(scpGet config.Scoped) (ScopedConfig, error)

ConfigByScopedGetter returns the internal configuration depending on the ScopedGetter. Mainly used within the middleware. If you have applied the option WithOptionFactory() the configuration will be pulled out only one time from the backend configuration service. The field optionInflight handles the guaranteed atomic single loading for each scope.

func (*Service) DebugCache

func (s *Service) DebugCache(w io.Writer) error

DebugCache uses Sprintf to write an ordered list (by scope.TypeID) into a writer. Only usable for debugging.

func (*Service) Options

func (s *Service) Options(opts ...Option) error

Options applies option at creation time or refreshes them.

func (*Service) WithRateLimit

func (s *Service) WithRateLimit(next http.Handler) http.Handler

WithRateLimit wraps an http.Handler to limit incoming requests. Requests that are not limited will be passed to the handler unchanged. Limited requests will be passed to the DeniedHandler. X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset and Retry-After headers will be written to the response based on the values in the RateLimitResult. The next handler may check an error with FromContextRateLimit().

type VaryBy

type VaryBy struct {
	// Vary by the RemoteAddr as specified by the net/http.Request field.
	RemoteAddr bool

	// Vary by the HTTP Method as specified by the net/http.Request field.
	Method bool

	// Vary by the URL's Path as specified by the Path field of the net/http.Request
	// URL field.
	Path bool

	// Vary by this list of header names, read from the net/http.Request Header field.
	Headers []string

	// Vary by this list of parameters, read from the net/http.Request FormValue method.
	Params []string

	// Vary by this list of cookie names, read from the net/http.Request Cookie method.
	Cookies []string

	// Use this separator string to concatenate the various criteria of the VaryBy struct.
	// Defaults to a newline character if empty (\n).
	Separator string

	// SafeUnicode enables the usage of unicode safe strings to lower functions.
	SafeUnicode bool
}

VaryBy defines the criteria to use to group requests.

func (*VaryBy) Key

func (vb *VaryBy) Key(r *http.Request) string

Key returns the key for this request based on the criteria defined by the VaryBy struct.

type VaryByer

type VaryByer interface {
	Key(*http.Request) string
}

VaryByer is called for each request to generate a key for the limiter. If it returns an empty string, all requests use an empty string key ;-). The rate limiter checks whether a particular key has exceeded a rate limit.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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