com.jamesward.zio_http_guard
Members list
Type members
Classlikes
Per-IP "suspect-request" sliding-window detector.
Per-IP "suspect-request" sliding-window detector.
Each IP has a small ring of timestamps (capped at BadActor.banOnRequestCount). A request marked suspect = true appends a timestamp; a request marked suspect = false is always Status.Allowed and never modifies the ring.
An IP is Status.Banned when the ring is full and the time between its oldest and newest timestamps fits inside BadActor.banWindow — i.e. the IP made banOnRequestCount suspect requests within banWindow.
The detector is purely a ZIO service over a ConcurrentMap. There is no background eviction; entries persist for the lifetime of the layer. For long-running servers this is fine: each entry is at most banOnRequestCount Instants plus a Ref wrapper.
Attributes
- Companion
- object
- Supertypes
-
trait Serializabletrait Producttrait Equalsclass Objecttrait Matchableclass AnyShow all
zio-http middleware that pairs the BadActor detector with a request pipeline:
zio-http middleware that pairs the BadActor detector with a request pipeline:
- Extract a client IP from the request (default: last value of
X-Forwarded-For, falling back torequest.remoteAddress). - Decide whether the request looks "suspect" (default: WordPress / PHP probing patterns in the path).
- Call BadActor.checkReq. If the IP is now banned, fail the request with a slow random-byte stream (a tarpit) so the attacker burns time reading garbage.
Apply with routes @@ BadActorMiddleware().
Attributes
- Supertypes
-
class Objecttrait Matchableclass Any
- Self type
-
BadActorMiddleware.type
Attributes
- Companion
- class
- Supertypes
-
trait Producttrait Mirrorclass Objecttrait Matchableclass Any
- Self type
-
CrawlerLimiter.type
Per-crawler "one active resource at a time" limiter.
Per-crawler "one active resource at a time" limiter.
Each known crawler User-Agent gets a single slot. While a slot is held, requests from that crawler for the same resource key (refresh the slot) and requests from that crawler for paths with no key (homepage, static assets, etc.) are allowed; requests for a different resource key are denied with 429 Too Many Requests until the slot's last access is older than hold.
The "resource key" is whatever you compute from the request — typically a coarse grouping that maps to an expensive backend operation. Examples:
- a Maven
groupId/artifactId/versiontriple, when each new triple triggers a fresh archive download + extraction - a tenant ID, when each new tenant warms an isolated cache
- a date bucket, when each bucket spans a separate database shard
Crawlers that don't legitimately need to walk the whole keyspace in parallel (Googlebot et al.) will simply move on to a different page from the same key while their slot is held; well-behaved crawlers absorb the limit invisibly.
Value parameters
- active
-
map from crawler User-Agent token to its currently held slot.
Attributes
- Companion
- object
- Supertypes
-
trait Serializabletrait Producttrait Equalsclass Objecttrait Matchableclass AnyShow all