"""Hooks that put a Guard in front of an agent's HTTP clients and browsers. A denied request raises EgressDenied (HTTP clients) or is aborted (browsers, proxy). A flagged request passes by default; pass on_flag=... to log it or raise. """ from .engine import EgressDenied, Guard def _decide(guard, url, method, on_flag=None, on_verdict=None): v = guard.check(url, method) if on_verdict: on_verdict(v) if v.decision == "deny": raise EgressDenied(v) if v.decision == "flag" and on_flag: on_flag(v) return v def guard_requests(session, guard=None, on_flag=None, on_verdict=None): """requests: check every request a Session sends (including redirects).""" guard = guard or Guard() send = session.send def guarded_send(request, **kwargs): _decide(guard, request.url, request.method, on_flag, on_verdict) return send(request, **kwargs) session.send = guarded_send return session def httpx_hook(guard=None, on_flag=None, on_verdict=None): """httpx: httpx.Client(event_hooks={"request": [httpx_hook()]}) (sync clients).""" guard = guard or Guard() def hook(request): _decide(guard, str(request.url), request.method, on_flag, on_verdict) return hook def httpx_async_hook(guard=None, on_flag=None, on_verdict=None): """httpx: httpx.AsyncClient(event_hooks={"request": [httpx_async_hook()]}).""" guard = guard or Guard() async def hook(request): _decide(guard, str(request.url), request.method, on_flag, on_verdict) return hook def _route_handler(guard, on_flag, on_verdict): def handler(route, request): try: _decide(guard, request.url, request.method, on_flag, on_verdict) except EgressDenied: return route.abort("blockedbyclient") return route.continue_() return handler def guard_playwright(context_or_page, guard=None, on_flag=None, on_verdict=None): """Playwright (sync API): guard_playwright(context) checks every request the browser makes.""" guard = guard or Guard() context_or_page.route("**/*", _route_handler(guard, on_flag, on_verdict)) return context_or_page async def guard_playwright_async(context_or_page, guard=None, on_flag=None, on_verdict=None): """Playwright (async API): await guard_playwright_async(context).""" guard = guard or Guard() async def handler(route, request): try: _decide(guard, request.url, request.method, on_flag, on_verdict) except EgressDenied: await route.abort("blockedbyclient") return await route.continue_() await context_or_page.route("**/*", handler) return context_or_page