4.2.3 — derive remote size from the data connection (#70)
Fixed
Redundant open-time size probe on remote HTTP sources (#70)
AVIOReader.open() fired a dedicated probeFileSize() round-trip (a Range: bytes=0-0 GET, falling back to HEAD) before opening the real data connection, even though that connection's own Range: bytes=0- request returns a 206 whose Content-Range already carries the total. On origins that omit a length for bytes=0-0 the probe paid a second HEAD round-trip, and that HEAD was the request some origins rate-limited (429), dropping an otherwise-fine source into seekless streaming mode (the failure chain reckloon reported: Range probe didn't yield a size, trying HEAD -> HEAD failed (HTTP 429), streaming mode).
The playback path now derives the size from the first data connection's response (206 Content-Range, or Content-Length on a from-0 2xx), folded in under the connection's existing lock, so the common case skips the probe entirely. Live skips it too: its result was discarded anyway (live size is non-authoritative) and the probe burned the full Range timeout on transcode endpoints that reject Range.
When the data connection resolves no usable size, the open does not drop straight to seekless streaming. It falls back to the exact prior probe path (Range: bytes=0- then HEAD) on a separate connection and budget, so:
- a transient 429 at open recovers to the seekable persistent reader once it clears (instead of permanently downgrading the session),
- a slow-header origin gets a fresh probe budget rather than being downgraded at the 15s mark,
- an origin whose length only comes via HEAD still resolves a size and stays seekable,
- only a genuinely length-less source (chunked / no
Content-Range, noContent-Length) streams, exactly as before.
The remaining still-extraction probe also switches bytes=0-0 to bytes=0- for the same one-shot win on origins that special-case the single-byte form.
Internally: the size is now written once from the connection's response (generation-guarded, non-live, write-once) and the open-time mode decision reads it and abandons the optimistic connection inside a single lock section, so the field stays race-free; sizeFromResponse never mistakes a 206's partial Content-Length for the total on an unknown (*) range.
Thanks to reckloon for the precise diagnosis, the real-world 429 failure chain, and the confirmed bytes=0- probe shape.
Full changelog: https://github.com/superuser404notfound/AetherEngine/blob/main/CHANGELOG.md