package tiny_httpd
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>
Minimal HTTP server using threads
Install
dune-project
Dependency
Authors
Maintainers
Sources
tiny_httpd-0.22.tbz
sha256=09fb93125c26b99f8714d0060dd3fb972046cde3ff935626d495b25e80543d8e
sha512=5751a0ac007c8cad11255d08b4915c8a8fb82ad33d28e58809ef1e29dc8c8f2fceb0dd15ecbe1fda5b5db2edbbc9479fa1d0690a4a25949e1d1b375ea13bd1a9
doc/src/tiny_httpd.core/headers.ml.html
Source file headers.ml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130open Common_ type t = (string * string) list let empty = [] (* [Char.lowercase_ascii] but easier to inline *) let[@inline] lower_char_ = function | 'A' .. 'Z' as c -> Char.unsafe_chr (Char.code c + 32) | c -> c (** Are these two header names equal? This is case insensitive *) let equal_name_ (s1 : string) (s2 : string) : bool = String.length s1 = String.length s2 && try for i = 0 to String.length s1 - 1 do let c1 = String.unsafe_get s1 i |> lower_char_ in let c2 = String.unsafe_get s2 i |> lower_char_ in if c1 <> c2 then raise_notrace Exit done; true with Exit -> false let contains name headers = List.exists (fun (n, _) -> equal_name_ name n) headers let list_contains_nocase_ name l = List.exists (equal_name_ name) l let rec get_exn ?(f = fun x -> x) x h = match h with | [] -> raise Not_found | (k, v) :: _ when equal_name_ x k -> f v | _ :: tl -> get_exn ~f x tl let get ?(f = fun x -> x) x h = try Some (get_exn ~f x h) with Not_found -> None let remove x h = List.filter (fun (k, _) -> not (equal_name_ k x)) h let set x y h = let h = if contains x h then remove x h else h in (x, y) :: h let pp out l = let pp_pair out (k, v) = Format.fprintf out "@[<h>%s: %s@]" k v in Format.fprintf out "@[<v>%a@]" (Format.pp_print_list pp_pair) l (* token = 1*tchar tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~" / DIGIT / ALPHA ; any VCHAR, except delimiters Reference: https://datatracker.ietf.org/doc/html/rfc7230#section-3.2 *) let is_tchar = function | '0' .. '9' | 'a' .. 'z' | 'A' .. 'Z' | '!' | '#' | '$' | '%' | '&' | '\'' | '*' | '+' | '-' | '.' | '^' | '_' | '`' | '|' | '~' -> true | _ -> false let for_all pred s = try String.iter (fun c -> if not (pred c) then raise Exit) s; true with Exit -> false let parse_line_ (line : string) : _ result = try let i = try String.index line ':' with Not_found -> failwith "invalid header, missing ':'" in let k = String.sub line 0 i in if not (for_all is_tchar k) then failwith (Printf.sprintf "Invalid header key: %S" k); let v = String.sub line (i + 1) (String.length line - i - 1) |> String.trim in Ok (k, v) with Failure msg -> Error msg open struct let nodup_ = [ "content-length"; "host"; "transfer-encoding" ] let is_nodup_ k = list_contains_nocase_ k nodup_ end let parse_ ~(buf : Buf.t) ?(max_headers = 100) ?(max_header_size = 16 * 1024) ?(max_total_size = 256 * 1024) (bs : IO.Input.t) : t = let rec loop acc count total_size = if count >= max_headers then bad_reqf 431 "too many headers (max: %d)" max_headers; if total_size >= max_total_size then bad_reqf 431 "headers too large (max: %d bytes)" max_total_size; match IO.Input.read_line_using_opt ~buf bs with | None -> raise End_of_file | Some "" -> assert false | Some "\r" -> acc | Some line when line.[String.length line - 1] <> '\r' -> bad_reqf 400 "bad header line, not ended in CRLF" | Some line -> let line_len = String.length line in if line_len > max_header_size then bad_reqf 431 "header too large (max: %d bytes)" max_header_size; let k, v = match parse_line_ line with | Ok r -> r | Error msg -> bad_reqf 400 "invalid header line: %s\nline is: %S" msg line in if is_nodup_ k && contains k acc then bad_reqf 400 "header %S is duplicated" k; loop ((k, v) :: acc) (count + 1) (total_size + line_len) in let headers = loop [] 0 0 in if contains "content-length" headers && get "transfer-encoding" headers = Some "chunked" then bad_reqf 400 "cannot specify both chunked encoding and content-length"; headers
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>