ByteRange
reads, resolves and writes Range header values in the bytes
range unit (RFC 9110 §14.1). A server answers a satisfiable range with a 206
carrying a ContentRange header, and an unsatisfiable one
with a 416.
(match (ByteRange.parse "bytes=0-499, -200")
(Result.Success specs)
(let [rs (ByteRange.resolve &specs 1000l)]
(if (Array.empty? &rs) (println* "416") (println* &rs)))
(Result.Error e) (IO.errorln &e))
parse
(Fn [(Ref String a)] (Result (Array ByteRangeSpec) String))
(parse s)
parses a Range header value into its range-specs, in header
order, as (Result (Array ByteRangeSpec) String).
Only the bytes range unit is understood; unit names are compared
case-insensitively. Whitespace around the commas of the range-set is ignored, as
are empty list elements (RFC 9110 §5.6.1.2). An unknown unit, an empty
range-set, and a spec that is syntactically invalid — including a last-pos
below its first-pos — all fail, which for a server means serving the whole
representation, since RFC 9110 §14.2 has it ignore the header field then.
resolve
(Fn [(Ref (Array ByteRangeSpec) a), Long] (Array (Pair Long Long)))
(resolve specs len)
maps specs and the length len of the representation to the
byte positions they select, as inclusive [first last] Pairs in spec order
(RFC 9110 §14.1.1).
A last-pos past the end clamps to len - 1, and a suffix-length of len or
more selects the whole representation. Specs that select nothing — a first-pos
at or past the end, a suffix-length of 0, anything at all when len is 0
— are dropped, so an empty result for a non-empty specs is the 416 Range Not Satisfiable case.