Documentation
¶
Index ¶
- Constants
- func CompressionMiddleware(config *CompressionConfig) httpcontract.Middleware
- func CorsMiddleware(config *CorsConfig) httpcontract.Middlewaredeprecated
- func DefaultClientIp(request httpcontract.Request) string
- func DefaultCompressionMiddleware() httpcontract.Middleware
- func DefaultCorsMiddleware() httpcontract.Middlewaredeprecated
- func IpRateLimit(requestsPerMinute int) httpcontract.Middleware
- func IpRateLimitWithResolver(requestsPerMinute int, clientIpResolver ClientIpResolver) httpcontract.Middleware
- func RateLimitMiddleware(config *RateLimitConfig) httpcontract.Middleware
- func RegisterRateLimitRequestListener(eventDispatcher eventcontract.EventDispatcher, config *RateLimitConfig)
- func RestrictiveCors(allowedOrigins ...string) httpcontract.Middlewaredeprecated
- func SimpleRateLimit(requestsPerMinute int) httpcontract.Middleware
- func SimpleRateLimitWithResolver(requestsPerMinute int, clientIpResolver ClientIpResolver) httpcontract.Middleware
- func StaticMiddleware(options *static.Options) httpcontract.Middleware
- func UserRateLimit(requestsPerMinute int, getUserId KeyExtractor) httpcontract.Middleware
- func UserRateLimitWithResolver(requestsPerMinute int, getUserId KeyExtractor, ...) httpcontract.Middleware
- type ClientIpResolver
- type CompressionConfig
- func (instance *CompressionConfig) ExcludedContentTypes() []string
- func (instance *CompressionConfig) ExcludedPaths() []string
- func (instance *CompressionConfig) Level() int
- func (instance *CompressionConfig) MinSize() int
- func (instance *CompressionConfig) SetExcludedContentTypes(excludedContentTypes []string)
- func (instance *CompressionConfig) SetExcludedPaths(excludedPaths []string)
- func (instance *CompressionConfig) SetLevel(level int)
- func (instance *CompressionConfig) SetMinSize(minSize int)
- type CorsConfigdeprecated
- func (instance *CorsConfig) AllowCredentials() bool
- func (instance *CorsConfig) AllowHeaders() []string
- func (instance *CorsConfig) AllowMethods() []string
- func (instance *CorsConfig) AllowOriginFunc() func(origin string) bool
- func (instance *CorsConfig) AllowOrigins() []string
- func (instance *CorsConfig) ExposeHeaders() []string
- func (instance *CorsConfig) MaxAge() int
- func (instance *CorsConfig) SetAllowHeaders(allowHeaders []string)
- func (instance *CorsConfig) SetAllowMethods(allowMethods []string)
- func (instance *CorsConfig) SetAllowOrigins(allowOrigins []string)
- type FixedWindowLimiter
- func NewFixedWindowLimiter(rate int, window time.Duration) *FixedWindowLimiter
- func NewFixedWindowLimiterWithClock(clockInstance clockcontract.Clock, rate int, window time.Duration) *FixedWindowLimiter
- func NewTokenBucketLimiter(rate int, window time.Duration) *FixedWindowLimiterdeprecated
- func NewTokenBucketLimiterWithClock(clockInstance clockcontract.Clock, rate int, window time.Duration) *FixedWindowLimiterdeprecated
- type KeyExtractor
- type OnLimitExceeded
- type RateLimitConfig
- func (instance *RateLimitConfig) ClientIpResolver() ClientIpResolver
- func (instance *RateLimitConfig) KeyExtractor() KeyExtractor
- func (instance *RateLimitConfig) Limiter() httpcontract.RateLimiter
- func (instance *RateLimitConfig) OnLimitExceeded() OnLimitExceeded
- func (instance *RateLimitConfig) SetClientIpResolver(resolver ClientIpResolver)
- func (instance *RateLimitConfig) SetKeyExtractor(keyExtractor KeyExtractor)
- func (instance *RateLimitConfig) SetOnLimitExceeded(onLimitExceeded OnLimitExceeded)
- type SlidingWindowLimiter
- type TokenBucketLimiterdeprecated
Constants ¶
const RateLimitRequestListenerPriority = 200
RateLimitRequestListenerPriority places the limiter ahead of the security chain: token resolution listens at 50 and access control at 20, so a request over budget is answered before it pays an authenticator round — and before a refusal ends the request without the middleware chain ever being built.
Variables ¶
This section is empty.
Functions ¶
func CompressionMiddleware ¶
func CompressionMiddleware(config *CompressionConfig) httpcontract.Middleware
func CorsMiddleware
deprecated
func CorsMiddleware(config *CorsConfig) httpcontract.Middleware
Deprecated: use github.com/precision-soft/melody/http/cors.Middleware instead.
func DefaultClientIp ¶ added in v1.11.0
func DefaultClientIp(request httpcontract.Request) string
func DefaultCompressionMiddleware ¶
func DefaultCompressionMiddleware() httpcontract.Middleware
func DefaultCorsMiddleware
deprecated
func DefaultCorsMiddleware() httpcontract.Middleware
Deprecated: use github.com/precision-soft/melody/http/cors.DefaultMiddleware instead.
func IpRateLimit ¶
func IpRateLimit(requestsPerMinute int) httpcontract.Middleware
IpRateLimit keys on the direct peer address, so behind a reverse proxy every client shares the proxy's single budget. It builds its config internally and returns only the middleware, so the resolver cannot be set afterwards: use IpRateLimitWithResolver with NewForwardedClientIpResolver where a trusted edge sits in front.
func IpRateLimitWithResolver ¶ added in v1.19.0
func IpRateLimitWithResolver( requestsPerMinute int, clientIpResolver ClientIpResolver, ) httpcontract.Middleware
IpRateLimitWithResolver is IpRateLimit with the client address read through the given resolver — pass NewForwardedClientIpResolver with the same policy handed to Kernel.SetForwardedHeadersPolicy so a per-IP budget behind a reverse proxy is charged to the client rather than to the proxy. A nil resolver keeps the direct peer.
func RateLimitMiddleware ¶
func RateLimitMiddleware(config *RateLimitConfig) httpcontract.Middleware
func RegisterRateLimitRequestListener ¶ added in v1.19.0
func RegisterRateLimitRequestListener( eventDispatcher eventcontract.EventDispatcher, config *RateLimitConfig, )
RegisterRateLimitRequestListener meters every request on kernel.request, before authentication and access control. RateLimitMiddleware meters only what reaches the handler path: a request the security chain refuses is answered before the middleware chain is built, so a burst of wrong credentials consumes no budget there. This door charges that burst and answers it once the budget is gone. The default key is the client address, which exists before any token is resolved; a key extractor reading the authenticated identity falls back the same way the middleware does. Both doors share the configuration, so registering both meters a request once per door — use distinct budgets or one door.
func RestrictiveCors
deprecated
func RestrictiveCors(allowedOrigins ...string) httpcontract.Middleware
Deprecated: use github.com/precision-soft/melody/http/cors.Restrictive instead.
func SimpleRateLimit ¶
func SimpleRateLimit(requestsPerMinute int) httpcontract.Middleware
SimpleRateLimit keys on the direct peer address, so behind a reverse proxy every client shares the proxy's single budget. It builds its config internally and returns only the middleware, so the resolver cannot be set afterwards: use SimpleRateLimitWithResolver with NewForwardedClientIpResolver where a trusted edge sits in front.
func SimpleRateLimitWithResolver ¶ added in v1.19.0
func SimpleRateLimitWithResolver( requestsPerMinute int, clientIpResolver ClientIpResolver, ) httpcontract.Middleware
SimpleRateLimitWithResolver is SimpleRateLimit with the client address read through the given resolver — pass NewForwardedClientIpResolver with the same policy handed to Kernel.SetForwardedHeadersPolicy so a per-IP budget behind a reverse proxy is charged to the client rather than to the proxy. A nil resolver keeps the direct peer.
func StaticMiddleware ¶
func StaticMiddleware( options *static.Options, ) httpcontract.Middleware
func UserRateLimit ¶
func UserRateLimit( requestsPerMinute int, getUserId KeyExtractor, ) httpcontract.Middleware
UserRateLimit falls back to the direct peer address for a request that carries no user id, so behind a reverse proxy every anonymous client shares the proxy's single budget. It builds its config internally and returns only the middleware, so the resolver cannot be set afterwards: use UserRateLimitWithResolver with NewForwardedClientIpResolver where a trusted edge sits in front.
func UserRateLimitWithResolver ¶ added in v1.19.0
func UserRateLimitWithResolver( requestsPerMinute int, getUserId KeyExtractor, clientIpResolver ClientIpResolver, ) httpcontract.Middleware
UserRateLimitWithResolver is UserRateLimit with the anonymous fallback address read through the given resolver — pass NewForwardedClientIpResolver with the same policy handed to Kernel.SetForwardedHeadersPolicy so unauthenticated traffic behind a reverse proxy is charged per client rather than to the proxy. A nil resolver keeps the direct peer.
Types ¶
type ClientIpResolver ¶ added in v1.11.0
type ClientIpResolver = func(httpcontract.Request) string
func NewForwardedClientIpResolver ¶ added in v1.16.0
func NewForwardedClientIpResolver(policy httpcontract.ForwardedHeadersPolicy) ClientIpResolver
NewForwardedClientIpResolver returns a ClientIpResolver that walks X-Forwarded-For right-to-left, skipping addresses that match the trusted proxy list, and returns the first untrusted address — the real client as attested by the trusted edge. It reuses the same ForwardedHeadersPolicy handed to Kernel.SetForwardedHeadersPolicy, so there is a single trusted-proxy list to maintain. It falls back to DefaultClientIp — the direct peer — whenever the forwarded chain cannot be trusted: forwarded headers are not trusted by policy, the trusted list is empty, the direct peer is not a trusted proxy (the header is then attacker-controlled), the chain has no parseable untrusted address, or every entry is a trusted proxy. Plug it into a rate-limit config with SetClientIpResolver so per-IP limits behind a reverse proxy key on the client instead of the proxy.
type CompressionConfig ¶
type CompressionConfig struct {
// contains filtered or unexported fields
}
func DefaultCompressionConfig ¶
func DefaultCompressionConfig() *CompressionConfig
func NewCompressionConfig ¶
func NewCompressionConfig( level int, minSize int, excludedContentTypes []string, excludedPaths []string, ) *CompressionConfig
func (*CompressionConfig) ExcludedContentTypes ¶
func (instance *CompressionConfig) ExcludedContentTypes() []string
func (*CompressionConfig) ExcludedPaths ¶
func (instance *CompressionConfig) ExcludedPaths() []string
func (*CompressionConfig) Level ¶
func (instance *CompressionConfig) Level() int
func (*CompressionConfig) MinSize ¶
func (instance *CompressionConfig) MinSize() int
func (*CompressionConfig) SetExcludedContentTypes ¶
func (instance *CompressionConfig) SetExcludedContentTypes(excludedContentTypes []string)
func (*CompressionConfig) SetExcludedPaths ¶
func (instance *CompressionConfig) SetExcludedPaths(excludedPaths []string)
func (*CompressionConfig) SetLevel ¶
func (instance *CompressionConfig) SetLevel(level int)
func (*CompressionConfig) SetMinSize ¶
func (instance *CompressionConfig) SetMinSize(minSize int)
type CorsConfig
deprecated
type CorsConfig struct {
// contains filtered or unexported fields
}
Deprecated: use github.com/precision-soft/melody/http/cors.Service instead.
func DefaultCorsConfig
deprecated
func DefaultCorsConfig() *CorsConfig
Deprecated: use github.com/precision-soft/melody/http/cors.DefaultService instead.
func NewCorsConfig
deprecated
func RestrictiveCorsConfig
deprecated
func RestrictiveCorsConfig(allowedOrigins []string) *CorsConfig
Deprecated: use github.com/precision-soft/melody/http/cors.RestrictiveService instead.
func (*CorsConfig) AllowCredentials ¶
func (instance *CorsConfig) AllowCredentials() bool
func (*CorsConfig) AllowHeaders ¶
func (instance *CorsConfig) AllowHeaders() []string
func (*CorsConfig) AllowMethods ¶
func (instance *CorsConfig) AllowMethods() []string
func (*CorsConfig) AllowOriginFunc ¶
func (instance *CorsConfig) AllowOriginFunc() func(origin string) bool
func (*CorsConfig) AllowOrigins ¶
func (instance *CorsConfig) AllowOrigins() []string
func (*CorsConfig) ExposeHeaders ¶
func (instance *CorsConfig) ExposeHeaders() []string
func (*CorsConfig) MaxAge ¶
func (instance *CorsConfig) MaxAge() int
func (*CorsConfig) SetAllowHeaders ¶
func (instance *CorsConfig) SetAllowHeaders(allowHeaders []string)
func (*CorsConfig) SetAllowMethods ¶
func (instance *CorsConfig) SetAllowMethods(allowMethods []string)
func (*CorsConfig) SetAllowOrigins ¶
func (instance *CorsConfig) SetAllowOrigins(allowOrigins []string)
type FixedWindowLimiter ¶ added in v1.19.0
type FixedWindowLimiter struct {
// contains filtered or unexported fields
}
func NewFixedWindowLimiter ¶ added in v1.19.0
func NewFixedWindowLimiter(rate int, window time.Duration) *FixedWindowLimiter
NewFixedWindowLimiter builds a limiter whose counters live in THIS process and nowhere else, which is the one thing to weigh before it guards anything that matters. The map is built at construction and dies with the process, so every restart hands each caller a full budget back — under a supervisor that restarts quickly, a limit of five per hour becomes five per restart — and it is not shared across replicas, so a limit of five is five per instance and the deployment enforces five times the number of them. That is the right trade for shaping ordinary traffic and the wrong one for login, one-time-password or password-reset routes, where the limit is a security control: those want a store the whole deployment sees, which is what integrations/rueidis.RateLimiter is — the distributed drop-in for these limiters. Melody says the same thing at boot about the two other defaults that live in the process, its cache backend and its session storage; it cannot say it about a limiter, because a limiter is wired by the application rather than by the framework.
func NewFixedWindowLimiterWithClock ¶ added in v1.19.0
func NewFixedWindowLimiterWithClock(clockInstance clockcontract.Clock, rate int, window time.Duration) *FixedWindowLimiter
func NewTokenBucketLimiter
deprecated
func NewTokenBucketLimiter(rate int, window time.Duration) *FixedWindowLimiter
Deprecated: use NewFixedWindowLimiter.
func NewTokenBucketLimiterWithClock
deprecated
func NewTokenBucketLimiterWithClock(clockInstance clockcontract.Clock, rate int, window time.Duration) *FixedWindowLimiter
Deprecated: use NewFixedWindowLimiterWithClock.
func (*FixedWindowLimiter) Allow ¶ added in v1.19.0
func (instance *FixedWindowLimiter) Allow(key string) bool
func (*FixedWindowLimiter) Close ¶ added in v1.19.0
func (instance *FixedWindowLimiter) Close() error
func (*FixedWindowLimiter) Reset ¶ added in v1.19.0
func (instance *FixedWindowLimiter) Reset(key string)
func (*FixedWindowLimiter) SetMaxKeys ¶ added in v1.19.0
func (instance *FixedWindowLimiter) SetMaxKeys(maxKeys int)
SetMaxKeys bounds how many distinct keys the limiter tracks. When the map is full and an idle-entry prune frees nothing, a request under an unseen key is denied rather than minting a bucket, so an attacker varying the key cannot grow the map without bound. A non-positive value is ignored.
type KeyExtractor ¶
type KeyExtractor = func(httpcontract.Request) string
type OnLimitExceeded ¶
type OnLimitExceeded = func(httpcontract.Request) (httpcontract.Response, error)
type RateLimitConfig ¶
type RateLimitConfig struct {
// contains filtered or unexported fields
}
func NewRateLimitConfig ¶
func NewRateLimitConfig( limiter httpcontract.RateLimiter, keyExtractor KeyExtractor, onLimitExceeded OnLimitExceeded, ) *RateLimitConfig
func (*RateLimitConfig) ClientIpResolver ¶ added in v1.11.0
func (instance *RateLimitConfig) ClientIpResolver() ClientIpResolver
func (*RateLimitConfig) KeyExtractor ¶
func (instance *RateLimitConfig) KeyExtractor() KeyExtractor
func (*RateLimitConfig) Limiter ¶
func (instance *RateLimitConfig) Limiter() httpcontract.RateLimiter
func (*RateLimitConfig) OnLimitExceeded ¶
func (instance *RateLimitConfig) OnLimitExceeded() OnLimitExceeded
func (*RateLimitConfig) SetClientIpResolver ¶ added in v1.11.0
func (instance *RateLimitConfig) SetClientIpResolver(resolver ClientIpResolver)
func (*RateLimitConfig) SetKeyExtractor ¶
func (instance *RateLimitConfig) SetKeyExtractor(keyExtractor KeyExtractor)
func (*RateLimitConfig) SetOnLimitExceeded ¶
func (instance *RateLimitConfig) SetOnLimitExceeded(onLimitExceeded OnLimitExceeded)
type SlidingWindowLimiter ¶
type SlidingWindowLimiter struct {
// contains filtered or unexported fields
}
func NewSlidingWindowLimiter ¶
func NewSlidingWindowLimiter(limit int, window time.Duration) *SlidingWindowLimiter
NewSlidingWindowLimiter holds its timestamps in THIS process, exactly as NewFixedWindowLimiter holds its counters: a restart returns every caller's full budget and each replica enforces the limit on its own, so the deployment allows the limit times the number of instances. Where the limit is a security control rather than traffic shaping, use the distributed drop-in in integrations/rueidis.
func NewSlidingWindowLimiterWithClock ¶
func NewSlidingWindowLimiterWithClock(clockInstance clockcontract.Clock, limit int, window time.Duration) *SlidingWindowLimiter
func (*SlidingWindowLimiter) Allow ¶
func (instance *SlidingWindowLimiter) Allow(key string) bool
func (*SlidingWindowLimiter) Close ¶
func (instance *SlidingWindowLimiter) Close() error
func (*SlidingWindowLimiter) Reset ¶
func (instance *SlidingWindowLimiter) Reset(key string)
func (*SlidingWindowLimiter) SetMaxKeys ¶ added in v1.19.0
func (instance *SlidingWindowLimiter) SetMaxKeys(maxKeys int)
SetMaxKeys bounds how many distinct keys the limiter tracks. When the map is full and an idle-entry prune frees nothing, a request under an unseen key is denied rather than minting a window, so an attacker varying the key cannot grow the map without bound. A non-positive value is ignored.
type TokenBucketLimiter
deprecated
type TokenBucketLimiter = FixedWindowLimiter
Deprecated: use FixedWindowLimiter. The limiter refills to full capacity at the window edge rather than proportionally to elapsed time, so it is a fixed-window counter and admits up to twice the rate across an instant straddling that edge; use SlidingWindowLimiter where the rate must hold over every trailing window.