MCPcopy Create free account
hub / github.com/Mnexa-AI/e2a / rateLimit

Method rateLimit

internal/httpapi/ratelimit.go:46–100  ·  view source on GitHub ↗

rateLimit is the Huma middleware that enforces the per-user poll limiter on reads and the per-IP registration limiter on agent create, and stamps the IETF RateLimit-Limit/Remaining/Reset headers (plus Retry-After on a 429) on the response. The per-agent SEND limiter is enforced inside the outbound h

(ctx huma.Context, next func(huma.Context))

Source from the content-addressed store, hash-verified

44// resolveOwnedAgent ownership check), which this middleware doesn't perform —
45// so the send limit is applied in deliver()/the outbound handlers, not here.
46func (s *Server) rateLimit(ctx huma.Context, next func(huma.Context)) {
47 op := ctx.Operation()
48 if op == nil {
49 next(ctx)
50 return
51 }
52
53 var snap RateSnapshot
54 var key string
55 switch {
56 case pollLimitedOps[op.OperationID] && s.deps.PollLimit != nil:
57 r := RequestFromContext(ctx.Context())
58 if r == nil || s.deps.Authenticator == nil {
59 next(ctx)
60 return
61 }
62 p, err := s.resolvePrincipal(r)
63 if err != nil {
64 // Unauthenticated: let the handler emit the canonical 401 rather
65 // than masking a missing credential as a rate-limit decision.
66 next(ctx)
67 return
68 }
69 snap, key = s.deps.PollLimit, p.User.ID
70 // Reuse the principal so the handler does not authenticate a second
71 // time on the hot read path.
72 ctx = huma.WithContext(ctx, withPrincipal(ctx.Context(), p))
73 case op.OperationID == "createAgent" && s.deps.RegLimit != nil:
74 r := RequestFromContext(ctx.Context())
75 if r == nil {
76 next(ctx)
77 return
78 }
79 snap, key = s.deps.RegLimit, clientIP(r)
80 default:
81 next(ctx)
82 return
83 }
84
85 ok, retryAfter, limit, remaining, reset := snap(key)
86 ctx.SetHeader("RateLimit-Limit", strconv.Itoa(limit))
87 ctx.SetHeader("RateLimit-Remaining", strconv.Itoa(remaining))
88 ctx.SetHeader("RateLimit-Reset", strconv.Itoa(reset))
89 if ok {
90 next(ctx)
91 return
92 }
93 secs := int(retryAfter.Round(time.Second).Seconds())
94 if secs < 1 {
95 secs = 1
96 }
97 ctx.SetHeader("Retry-After", strconv.Itoa(secs))
98 writeEnvelope(ctx, NewError(http.StatusTooManyRequests, "rate_limited",
99 "rate limit exceeded").WithDetails(map[string]any{"retry_after_seconds": secs}))
100}
101
102// writeEnvelope serializes an error envelope directly to the response from a
103// middleware, where there is no handler return value for Huma to render. It

Callers

nothing calls this directly

Calls 7

resolvePrincipalMethod · 0.95
RequestFromContextFunction · 0.85
withPrincipalFunction · 0.85
writeEnvelopeFunction · 0.85
NewErrorFunction · 0.85
WithDetailsMethod · 0.80
clientIPFunction · 0.70

Tested by

no test coverage detected