The Anti-Bot Technique: Cooperative Rendering with Blazeio
The Discovery
While working with Blazeio (a Python async web framework with true zero-buffering streaming), I stumbled upon this technique - and it's so stupidly effective it feels like cheating.
The magic code: ``` import Blazeio as io import Blazeio.Other.proxy as proxy import Blazeio.Modules.onrender as onrender
io.INBOUND_CHUNK_SIZE, io.OUTBOUND_CHUNK_SIZE = 1024100, 1024100
io.Scope.add_imports(globals())
io.Scope.web = io.App("0.0.0.0", 9001, with_keepalive = 1)
class Element: __slots__ = ("r", "element", "className") def __init__(app, r: io.BlazeioProtocol, element: str, className: str = None): app.r, app.element, app.className = r, element.encode(), b'class="%b"' % className.encode() if className else b''
async def __aenter__(app):
await app.r.write(b'<%b %b>' % (app.element, app.className))
return app
async def __aexit__(app, *args):
await app.r.write(b'</%b>' % app.element)
return False
async def text(app, text: str):
return await app.r.write(text.encode())
class Dom:
__slots__ = ("r", "event", "id")
def __init__(app, r: io.BlazeioProtocol):
app.r = r
app.event = io.SharpEvent()
app.id = io.token_urlsafe(11) async def __aenter__(app):
await app.r.write(b'<!DOCTYPE html>\n<html lang="en">\n<head>\n<meta charset="UTF-8">\n<meta name="viewport" content="width=device-width, initial-scale=1.0">\n<title>Dynamic Rendering</title>\n<link rel="stylesheet" href="/get/favicon?id=%b" fetchpriority="high">\n</head>\n<body>\n' % app.id.encode())
return app
async def __aexit__(app, *args):
await app.r.write(b'\n</body>\n</html>')
return False
def __await__(app):
yield from app.event.wait_clear().__await__()
return app
def element(app, *args, **kwargs):
return Element(app.r, *args, **kwargs)
@io.Scope.web.attach
class Main:
__slots__ = ()
events = io.ddict()
def __init__(app):
... async def _get_favicon(app, r: io.BlazeioProtocol):
if not (dom := app.events.pop(r.params().get("id"), None)): raise io.Abort("Not found", 404)
dom.event.set()
await io.Deliver.text("True")
async def _(app, r: io.BlazeioProtocol):
await r.prepare({"Content-type": "text/html", "Transfer-encoding": "chunked"}, 200)
async with Dom(r) as dom:
app.events[dom.id] = dom
await dom
async with dom.element("main") as element:
await element.text("Hello world")
if __name__ == "__main__":
with io.Scope.web:
io.Scope.web.runner()
```How It Works
For Real Browsers:
1. Browser requests / 2. Server streams: <!DOCTYPE...<link rel="stylesheet" href="/get/favicon?id=UNIQUE_ID"> 3. Browser naturally fetches the "stylesheet" (actually our trigger endpoint) 4. Server receives the trigger request and continues rendering: <main>Hello world</main> 5. User sees complete page
For Bots:
1. Bot requests / 2. Server streams: <!DOCTYPE...<link rel="stylesheet" href="/get/favicon?id=UNIQUE_ID"> 3. Bot doesn't fetch the "stylesheet" (or fetches it too late) 4. Server stops rendering at <body> 5. Bot sees incomplete page and gives up