Skip to content

angee.storage.uploads

ORM-free byte helpers shared by the storage upload flow.

The upload behavior lives on the model (File.objects.draft, File.receive_bytes / File.finalize); this module holds only the token constants and byte-level helpers they compose with — stream hashing, MIME detection, and the capped body reader. Keeping it free of any model import is what lets models.py import from here without a cycle.

FALLBACK_MIME

MIME used when libmagic yields nothing; also the guaranteed catalogue row.

UPLOAD_TOKEN_MAX_AGE

Seconds a proxy upload token stays valid.

UPLOAD_TOKEN_SALT

Signing salt namespacing proxy upload tokens.

UPLOAD_TOKEN_HEADER

Request header carrying the proxy upload token.

DOWNLOAD_TOKEN_MAX_AGE

Seconds a proxy download token stays valid.

DOWNLOAD_TOKEN_SALT

Signing salt namespacing proxy download tokens.

DOWNLOAD_TOKEN_HEADER

Request header carrying the proxy download token.

PROXY_CHUNK_SIZE

Bytes per read while streaming a proxied body into the backend.

MIME_SNIFF_BYTES

Head bytes captured during finalize hashing for MIME detection.

sha256_stream

python
def sha256_stream(reader: BinaryIO,
                  *,
                  capture_head: int = 0) -> tuple[str, int, bytes]

Stream-hash a binary reader without materializing it.

Returns (hex_digest, total_bytes, head_bytes); head_bytes is the first capture_head bytes so callers can sniff MIME without a second read.

detect_mime

python
def detect_mime(payload: bytes, filename: str = "") -> str

Detect a MIME type for a stored object.

libmagic sniffs the head bytes and is authoritative when it recognises the content. It does not know every format (e.g. HEIC on older magic databases), so when it yields nothing we fall back to the filename extension via the stdlib mimetypes registry, so the row still carries a useful type instead of the generic catch-all.

BodyTooLarge

python
class BodyTooLarge(Exception)

Internal sentinel raised by :class:CappedReader when the cap trips.

CappedReader

python
class CappedReader()

File-like wrapper that aborts once more than max_bytes are read.

Streams a request body into Storage.save without materializing it; Django's File wrapper only needs read(size). Overflow raises the private :class:BodyTooLarge sentinel so the caller can clean up the partial backend object before answering with an API error.

__init__

python
def __init__(reader: BinaryIO, *, max_bytes: int) -> None

Wrap reader with a hard byte cap.

read

python
def read(size: int = -1) -> bytes

Read up to size bytes, raising :class:BodyTooLarge on overflow.

close

python
def close() -> None

Close the wrapped reader when it supports closing.

Released under the AGPL-3.0 License.