Request Lifecycle
This page explains the order in which IPGuardian.Check evaluates a request, and the status code and error message each step returns.
Check Order
graph TB
A[getDevice] -->|fails| E500[500 Failed to get device info]
A --> T{Trust?}
T -->|yes| OK[200]
T -->|no| B{Block?}
B -->|yes| F1[403 Device is blocked]
B -->|no| N{Ban?}
N -->|yes| F2[403 Device is banned]
N -->|no| S[dynamicScore]
S -->|score >= 100| F3[403 Device is blocked]
S --> RL{Rate limit}
RL -->|over| F4[403 rate limit]
RL -->|within| OK
| Step | Condition | Result |
|---|---|---|
| 1 | IP cannot be resolved or session cannot be signed | 500, Failed to get device info |
| 2 | IP is on the Allow list | 200, skips every later step |
| 3 | IP is within a Block period | 403, Device is blocked, IP: {ip} |
| 4 | IP is on the Deny list | 403, Device is banned, IP: {ip} |
| 5 | Combined score >= 100 |
403, Device is blocked, IP: {ip} |
| 6 | Score >= ScoreDangerous and per-minute requests >= RateLimitDangerous |
403, ... rate limit (Dangerous) ... |
| 7 | Score >= ScoreSuspicious and per-minute requests >= RateLimitSuspicious |
403, ... rate limit (Suspicious) ... |
| 8 | Per-minute requests >= RateLimitNormal |
403, ... rate limit (Normal) ... |
| 9 | None of the above | 200 |
Side Effects on Every Check
getDevice runs before any list check, so these happen even when the request is rejected:
| Side effect | Detail |
|---|---|
frequency:{ip}:{minute} increments |
Per-minute request count, windowed by Unix minute rather than sliding |
Two Set-Cookie headers |
conn.sess.id and conn.device.id, refreshed on every request |
block:count:{ip} increments |
Only while the IP is blocked |
The scoring step also writes each dimension's Redis sets and lists; see Redis Keys.
Effective Rate Limits
The count includes the current request and compares with >=, so a setting of N admits at most N - 1 requests per minute. With defaults:
| Tier | Setting | Admitted per minute |
|---|---|---|
| Normal | 100 |
99 |
| Suspicious | 50 |
49 |
| Dangerous | 20 |
19 |
Windows split on whole Unix minutes and reset at the boundary, so a burst straddling two minutes can pass up to roughly twice the limit.
Error-Handling Boundaries
| Case | Behavior |
|---|---|
| Redis fails during scoring | dynamicScore returns nil plus an error; Check only logs it, then reads score.IsBlock and panics with a nil pointer dereference; see Known Issues |
| Allow/Deny Redis lookup fails | Falls back to the memory cache |
| Block Redis lookup fails | Treated as not blocked (fail-open) |
| Per-minute count fails | Count treated as 1 |
Response Format
Check returns IPGuardianResult; both middlewares turn a failure into JSON:
{"error": "Device is banned, IP: 198.51.100.77"}
To call Check yourself, see Middleware.