Archive hosting
A .rtla archive (the streamed-archive format, ADR 0062) is a network transport for
renderable silicon: a header, a tile directory, and byte-contiguous tiles, so a
browser fetches exactly one tile with a single HTTP Range request. Two pieces of
infrastructure put those archives on the open web safely: a Cloudflare Worker that
serves the bytes, and an xtask gate that decides which archives are allowed to be
staged for hosting in the first place.
The serving Worker
worker/archive/ is a Cloudflare Worker with an R2 binding to the private bucket
reticle-archives. It is separate from the collaboration relay in worker/ (a
Durable Object); the two share nothing and deploy independently.
- Served through the binding, never the public URL. The bucket is reached only
through the Worker’s R2 binding, never the rate-limited public
r2.devURL, so the archives stay off the rate-limited path and behind the Worker’s CORS lock. - Range. A
Range: bytes=a-brequest is answered206 Partial Contentwith aContent-Rangeheader and exactly those bytes; a request with noRangereturns the whole object as200.Accept-Ranges: bytesis always advertised. This is the point of the format: one tile is one Range request over its[offset, offset+len)slice of the archive. - Cache. The Cache API sits in front, keyed by object key plus requested range,
so each distinct byte range is cached as its own entry. Because the Cache API will
not store a
206or aContent-Rangeresponse, a ranged body is cached as a normalized200that records the real status and range in internal headers, then reconstructed on a hit. - CORS.
Access-Control-Allow-Originis locked to the Pages originhttps://alpharomerojl.github.io(never*), and anOPTIONSpreflight is answered204with the allowed methods and headers.
The Range header is untrusted
The Range header is attacker controlled, so the parser (worker/archive/src/range.js)
is the trust boundary between the network and the R2 read. It resolves every input to
one of three verdicts: serve the whole object, serve a bounded [offset, offset+len)
slice already clamped to the object size, or reject. A malformed, backwards, or
overflowing range is answered 416 Range Not Satisfiable with
Content-Range: bytes */size, never a silent full transfer and never an out-of-range
read. Every satisfiable range is clamped to the object, so the Worker can never be
driven to read past the object or to request an absurd length. The parser is covered
by a node --test unit suite; a wrangler dev local ranged fetch is the hermetic
integration check (see worker/archive/README.md).
The redistribution license gate
Before an archive is staged for hosting, xtask verify-licenses <dir> decides whether
it may be redistributed at all. For every *.rtla archive in a staged content
directory it reads a sibling NOTICE manifest (<archive>.rtla.NOTICE, the provenance
style of corpus/tinytapeout/NOTICE.md: a Source: URL and an
SPDX-License-Identifier:), and it verifies the SPDX license is on a small
redistribution allowlist:
Apache-2.0,MIT,CC-BY-4.0- the CERN Open Hardware Licence family (
CERN-OHL-S,-W,-P, any variant) - public-domain dedications (
CC0-1.0,Unlicense,public-domain)
The gate fails closed: an archive ships only when its license is positively
verified. Any archive whose terms cannot be verified is EXCLUDED, with a printed
STATUS EXCLUDED line naming the reason: no manifest, no SPDX line, a compound SPDX
expression the gate will not guess at, or a license not on the allowlist. A run that
excludes anything exits non-zero, so a staging step that would ship unverifiable
content fails loudly:
STATUS VERIFIED good.rtla (Apache-2.0) [https://github.com/TinyTapeout/tinytapeout-03]
STATUS EXCLUDED mystery.rtla: license not on redistribution allowlist: NoSuchLicense-9.9
STATUS EXCLUDED orphan.rtla: no license manifest (expected orphan.rtla.NOTICE)
verify-licenses: 3 archive(s): 1 verified, 2 excluded