An OCaml webserver, but the allocating version (vs httpz which doesnt)
at main 126 lines 3.6 kB view raw
1(** Range request parsing and Content-Range response writing per RFC 7233. *) 2 3(** {1 Types} *) 4 5(** A single byte range specification. 6 Use query functions ([is_range], [is_suffix], [is_open]) to inspect the kind. *) 7type byte_range = 8 { kind : int 9 ; start : int64 10 ; end_ : int64 11 } 12 13(** Maximum number of ranges that can be parsed. *) 14val max_ranges : int 15 16(** Empty byte_range for array initialization. *) 17val empty : byte_range 18 19(** {2 Range Queries} *) 20 21(** Returns true if this is a standard range with explicit start and end. *) 22val is_range : byte_range -> bool 23 24(** Returns true if this is a suffix range (last N bytes). *) 25val is_suffix : byte_range -> bool 26 27(** Returns true if this is an open-ended range (start to EOF). *) 28val is_open : byte_range -> bool 29 30(** Parse status. *) 31type parse_status = 32 | Valid 33 | Invalid 34 35(** A resolved byte range with concrete start/end positions. *) 36type resolved = 37 { start : int64 (** First byte position (0-indexed) *) 38 ; end_ : int64 (** Last byte position (inclusive) *) 39 ; length : int64 (** Number of bytes: end_ - start + 1 *) 40 } 41 42(** Empty resolved range for array initialization. *) 43val empty_resolved : resolved 44 45(** Range evaluation result. *) 46type eval_result = 47 | Full_content (** Serve full content *) 48 | Single_range (** Single range - use first resolved *) 49 | Multiple_ranges (** Multiple ranges - use resolved array *) 50 | Not_satisfiable (** 416 error *) 51 52(** {1 Parsing} *) 53 54(** Parse Range header value into array of byte_ranges. 55 Returns (status, count) where count is number of ranges parsed. 56 Only supports "bytes" unit. *) 57val parse 58 : Base_bigstring.t 59 -> Span.t 60 -> byte_range array 61 -> parse_status * int 62 63(** Parse Range header from a string. Creates a local buffer internally. *) 64val parse_string : string -> byte_range array -> parse_status * int 65 66(** {1 Range Resolution} *) 67 68(** Evaluate ranges and determine result. 69 Returns (result, resolved_count). 70 Resolved ranges are written to the output array. *) 71val evaluate 72 : byte_range array 73 -> count:int 74 -> resource_length:int64 75 -> resolved array 76 -> eval_result * int 77 78(** Resolve a single byte_range against resource length. 79 Returns (valid, resolved) where valid indicates if range is satisfiable. *) 80val resolve_range 81 : byte_range 82 -> resource_length:int64 83 -> bool * resolved 84 85(** {1 Response Writing} *) 86 87(** Write [Accept-Ranges: bytes\r\n] header. Returns new offset. *) 88val write_accept_ranges : Base_bigstring.t -> off:int -> int 89 90(** Write [Accept-Ranges: none\r\n] header. Returns new offset. *) 91val write_accept_ranges_none : Base_bigstring.t -> off:int -> int 92 93(** Write [Content-Range: bytes start-end/total\r\n] header. *) 94val write_content_range 95 : Base_bigstring.t 96 -> off:int 97 -> start:int64 98 -> end_:int64 99 -> total:int64 100 -> int 101 102(** Write Content-Range header from resolved range. *) 103val write_content_range_resolved 104 : Base_bigstring.t 105 -> off:int 106 -> resolved 107 -> total:int64 108 -> int 109 110(** Write [Content-Range: bytes * /total\r\n] header for 416 responses. *) 111val write_content_range_unsatisfiable 112 : Base_bigstring.t 113 -> off:int 114 -> total:int64 115 -> int 116 117(** {1 Multipart Helpers} *) 118 119(** Write multipart boundary line: [--boundary\r\n]. *) 120val write_multipart_boundary : Base_bigstring.t -> off:int -> boundary:string -> int 121 122(** Write final multipart boundary: [--boundary--\r\n]. *) 123val write_multipart_final : Base_bigstring.t -> off:int -> boundary:string -> int 124 125(** Generate a random boundary string suitable for multipart responses. *) 126val generate_boundary : unit -> string