You are analyzing an in-memory request history for a web platform. Each record includes three fields: timestamp (an ISO-8601 UTC timestamp), request_ip (an IPv4 client address), and host (the requested hostname). The records are already sorted by timestamp in ascending order, and the whole history fits in memory.
For a request at time t, only earlier records whose timestamps satisfy are considered. A record exactly at is not within the window. Requests that are blocked are still kept in the history and can affect later decisions. If several records share the same timestamp, process them in their original input order.
Part 1 — per-IP limiting:
A request from IP x is blocked when the number of earlier window records from x is at least IPReqMax.
Part 2 — combined per-IP and per-(IP, host) limiting:
A request from IP x to host h is blocked when at least one of the following is true:
x is at least IPReqMax, orx to h is at least IPHostReqMax.If a request violates both rules, it counts as one blocked request.
Return an array of two integers: [blocked_per_ip_only, blocked_combined]. When IPHostReqMax is omitted or null, the second value is computed under the per-IP rule only.
Example 1:
Input:
logs = [
["2025-07-01T00:00:00Z", "203.0.113.9", "api.site-a.dev"],
["2025-07-01T00:00:10Z", "203.0.113.9", "api.site-b.dev"],
["2025-07-01T00:00:20Z", "203.0.113.9", "api.site-a.dev"],
["2025-07-01T00:00:30Z", "203.0.113.9", "api.site-b.dev"],
["2025-07-01T00:00:31Z", "203.0.113.9", "api.site-a.dev"],
["2025-07-01T00:01:01Z", "203.0.113.9", "api.site-c.dev"]
]
T = 30
IPReqMax = 2
IPHostReqMax = null
Output: [3, 3]
Explanation: The requests at 00:00:20, 00:00:30, and 00:00:31 are blocked. The request at 00:00:30 is blocked even though 00:00:00 is exactly 30 seconds earlier, because that timestamp is outside the window.
logs = [["2025-07-01T00:00:00Z","203.0.113.9", "api.site-a.dev"], ["2025-07-01T00:00:10Z", "203.0.113.9", "api.site-b.dev"], ["2025-07-01T00:00:20Z", "203.0.113.9", "api.site-a.dev"], ["2025-07-01T00:00:30… T = 30 IPReqMax = 2 IPHostReqMax = null
[3,3]
| 0 | 1 | 2 | 3 | |
|---|---|---|---|---|
| 0 | #0 | 00:00… | 203.0… | api.s… |
| 1 | #1 | 00:00… | 203.0… | api.s… |
| 2 | #2 | 00:00… | 203.0… | api.s… |
| 3 | #3 | 00:00… | 203.0… | api.s… |
| 4 | #4 | 00:00… | 203.0… | api.s… |
| 5 | #5 | 00:01… | 203.0… | api.s… |
Six requests from IP 203.0.113.9, already sorted by timestamp. Window T = 30s, IPReqMax = 2, IPHostReqMax = null.
Example 2:
Input:
logs = [
["2025-08-01T00:00:00Z", "198.51.100.20", "shop.example"],
["2025-08-01T00:00:05Z", "198.51.100.20", "mail.example
logs = [["2025-07-01T00:00:00Z","203.0.113.9", "api.site-a.dev"], ["2025-07-01T00:00:10Z", "203.0.113.9", "api.site-b.dev"], ["2025-07-01T00:00:20Z", "203.0.113.9", "api.site-a.dev"], ["2025-07-01T00:00:30… T = 30 IPReqMax = 2 IPHostReqMax = null
[3,3]
| 0 | 1 | 2 | 3 | |
|---|---|---|---|---|
| 0 | #0 | 00:00… | 203.0… | api.s… |
| 1 | #1 | 00:00… | 203.0… | api.s… |
| 2 | #2 | 00:00… | 203.0… | api.s… |
| 3 | #3 | 00:00… | 203.0… | api.s… |
| 4 | #4 | 00:00… | 203.0… | api.s… |
| 5 | #5 | 00:01… | 203.0… | api.s… |
Six requests from IP 203.0.113.9, already sorted by timestamp. Window T = 30s, IPReqMax = 2, IPHostReqMax = null.