blackbull.middleware¶
blackbull.middleware
¶
Public middleware exports.
Legacy Middleware-suffixed aliases and compress emit DeprecationWarning; use the unsuffixed classes for new code.
CORS
¶
Cross-Origin Resource Sharing (CORS) middleware.
Handles preflight OPTIONS requests and attaches CORS headers to actual
cross-origin responses. Requests without an Origin header pass through
unchanged.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
allow_origins
|
list[str] | str
|
Explicit origin strings or |
'*'
|
allow_methods
|
list[str] | None
|
HTTP methods permitted in cross-origin requests.
Defaults to |
None
|
allow_headers
|
list[str] | str
|
Request headers permitted; |
'*'
|
allow_credentials
|
bool
|
Emit |
False
|
expose_headers
|
list[str] | None
|
Response headers the browser JS may read. |
None
|
max_age
|
int | None
|
Preflight cache lifetime in seconds. |
600
|
Usage::
app = BlackBull()
app.use(CORS(
allow_origins=['https://myapp.example.com'],
allow_credentials=True,
max_age=3600,
))
__init__(allow_origins='*', allow_methods=None, allow_headers='*', allow_credentials=False, expose_headers=None, max_age=600)
¶
Build the middleware.
allow_credentials=True cannot be combined with
allow_origins=['*']: the pair raises ValueError. A wildcard
origin with credentials is what the CORS specification forbids, not
something this middleware chooses to refuse.
Cache
¶
Per-worker in-memory response cache.
Compression
¶
ASGI middleware: compress the response body using the best codec the client accepts (br > zstd > gzip, in server-preference order).
Bodies smaller than min_size bytes are forwarded uncompressed. Responses with already-compressed Content-Types (image/, video/, etc.) are forwarded uncompressed. brotli and zstandard are optional — if not installed the middleware falls back gracefully to gzip or no compression.
BlackBull middleware convention::
from blackbull.middleware import Compression
@app.route(path='/', middlewares=[Compression()])
async def handler(conn, receive, send): ...
StaticFiles
¶
Serve files from one directory, as route middleware or on its own.
app.static(url_prefix, root_dir) attaches it to a route; called with
three arguments instead of four it is a plain ASGI app that can be mounted
anywhere. The difference shows up on a miss: with a call_next the
request continues down the chain, and without one it is answered 404.
Only GET and HEAD are served. A resolved path outside the root is
a 400, checked after symlinks are followed, so a link pointing out of the
tree does not escape it. Under BLACKBULL_ENV=production nothing is
served at all — a production deployment is expected to have a proxy or CDN
in front, and two things serving the same files is the problem being
avoided.
What a hit produces depends on the request and on what is on disk. ETag
and Last-Modified are emitted unless conditional is off, and a matching
If-None-Match / If-Modified-Since gets a 304 without the body being
read. A Range request gets a 206, or a 416 when the range is
unsatisfiable. A precompressed sibling (app.js.br, .zst, .gz)
is served in place of the original when the client accepts that encoding
and the request is not a range request; those responses carry
Vary: Accept-Encoding. Files larger than four megabytes stream in
chunks rather than being read whole, so peak memory does not follow file
size.
docs/guide/static-files.md covers the choices this leaves open — the
opt-in cache in particular, and why it is off by default.
__init__(directory=None, *, url_prefix='', root_dir=None, cache=False, index=None, conditional=True)
¶
Serve directory or root_dir; at least one must be supplied.
index=None disables directory indexes. cache=True holds small bodies in a bounded per-worker cache; its validation TTL can delay on-disk edits. conditional=False disables validators and 304 responses. See docs/guide/static-files.md for cache, traversal and production-mode limits.
TrustedProxy
¶
Rewrite conn.client and conn.scheme only behind configured trusted peers.
Proxies must append the observed peer or overwrite the chain. Standalone proto/prefix assertions must replace client-supplied values. Forwarded takes precedence over X-Forwarded-For/Proto; walk right to left to the first untrusted IP. Trust defaults to loopback. See the reverse-proxy guide.
as_middleware(target)
¶
Decorate a function or class with (conn, receive, send, call_next) middleware.
Normalize downstream HTTP sends to NativeResponse before the middleware's send wrapper. A first request parameter named scope opts into ASGI scope and event dictionaries at both edges, including WebSocket events. Omit the decorator to handle raw downstream send arguments.