An OCaml webserver, but the allocating version (vs httpz which doesnt)
at main 88 lines 3.4 kB view raw
1(** Parser combinators for HTTP/1.1 parsing. *) 2 3(** Parse error with detailed status. Alias for {!Err.Parse_error}. *) 4exception Parse_error of Buf_read.status 5 6(** Parser state holding buffer and length. *) 7type pstate = { buf : Base_bigstring.t; len : int } 8 9(** {1 Core Functions} *) 10 11(** Create parser state from buffer and length *) 12val make : Base_bigstring.t -> len:int -> pstate 13 14(** Remaining bytes at position *) 15val remaining : pstate -> pos:int -> int 16 17(** Check if at end of buffer *) 18val at_end : pstate -> pos:int -> bool 19 20(** {1 Basic Combinators} *) 21 22(** Peek current char without advancing. Raises [Partial] if at end. *) 23val peek_char : pstate -> pos:int -> char 24 25(** Peek char at offset from current position. Raises [Partial] if out of bounds. *) 26val peek_at : pstate -> pos:int -> int -> char 27 28(** Match single character, return new position. Raises [Partial] or [Malformed]. *) 29val char : char -> pstate -> pos:int -> int 30 31(** Match literal string, return new position. Raises [Partial] or [Malformed]. *) 32val string : string -> pstate -> pos:int -> int 33 34(** Take chars while predicate holds, return span and new position. *) 35val take_while : (char -> bool) -> pstate -> pos:int -> Span.t * int 36 37(** Skip chars while predicate holds, return new position. *) 38val skip_while : (char -> bool) -> pstate -> pos:int -> int 39 40(** Take exactly n chars as span, return span and new position. Raises [Partial]. *) 41val take : int -> pstate -> pos:int -> Span.t * int 42 43(** Skip exactly n chars, return new position. Raises [Partial]. *) 44val skip : int -> pstate -> pos:int -> int 45 46(** Match char satisfying predicate, return char and new position. *) 47val satisfy : (char -> bool) -> pstate -> pos:int -> char * int 48 49(** Try parser, return None and original pos on failure. *) 50val optional : (pstate -> pos:int -> 'a * int) -> pstate -> pos:int -> 'a option * int 51 52(** {1 HTTP-Specific Combinators} *) 53 54(** Match CRLF (\\r\\n), return new position. *) 55val crlf : pstate -> pos:int -> int 56 57(** Match SP (space), return new position. *) 58val sp : pstate -> pos:int -> int 59 60(** Take HTTP token chars (for method, header names), return span and new position. 61 Must be non-empty. Raises [Malformed] if empty. *) 62val token : pstate -> pos:int -> Span.t * int 63 64(** Skip optional whitespace (OWS = SP / HTAB), return new position. *) 65val ows : pstate -> pos:int -> int 66 67(** Parse HTTP version (HTTP/1.0 or HTTP/1.1), return version and new position. *) 68val http_version : pstate -> pos:int -> Version.t * int 69 70(** Parse HTTP method from token, return method and new position. *) 71val parse_method : pstate -> pos:int -> Method.t * int 72 73(** Parse request target, return span and new position. Raises [Invalid_target] if empty. *) 74val parse_target : pstate -> pos:int -> Span.t * int 75 76(** Parse request line: METHOD SP target SP version CRLF. 77 Returns (method, target_span, version, new_pos). *) 78val request_line : pstate -> pos:int -> Method.t * Span.t * Version.t * int 79 80(** Parse a single header line. 81 Returns (header_name, name_span, value_span, new_pos). *) 82val parse_header : pstate -> pos:int -> Header_name.t * Span.t * Span.t * int 83 84(** Check if at end of headers (CRLF at current position). *) 85val is_headers_end : pstate -> pos:int -> bool 86 87(** Skip the empty line at end of headers, return new position. *) 88val end_headers : pstate -> pos:int -> int