@@ -50,6 +50,63 @@ let respond_string ?headers ~status ~body () =
5050let respond_error ?headers ?(status = `Internal_server_error ) ~body () =
5151 respond_string ?headers ~status ~body: (" Error: " ^ body) ()
5252
53+ let respond_not_found ?uri () =
54+ let body =
55+ match uri with
56+ | None -> " Not found"
57+ | Some uri -> " Not found: " ^ Uri. to_string uri
58+ in
59+ respond_string ~status: `Not_found ~body ()
60+
61+ let respond_file ?headers ?(status = `OK ) fname =
62+ let exception Isnt_a_file in
63+ (* Copied from [cohttp-lwt-unix] and adapted to [Body]. *)
64+ Lwt. catch
65+ (fun () ->
66+ (* Check this isn't a directory first *)
67+ let * () =
68+ let * s = Lwt_unix. stat fname in
69+ if Unix. (s .st_kind <> S_REG)
70+ then raise Isnt_a_file
71+ else Lwt. return_unit
72+ in
73+ let count = 16384 in
74+ let * ic =
75+ Lwt_io. open_file ~buffer :(Lwt_bytes. create count ) ~mode :Lwt_io. input
76+ fname
77+ in
78+ let * len = Lwt_io. length ic in
79+ let encoding = Http.Transfer. Fixed len in
80+ let stream write =
81+ let rec cat_loop () =
82+ Lwt. bind (Lwt_io. read ~count ic ) (function
83+ | "" -> Lwt. return_unit
84+ | buf -> Lwt. bind (write buf ) cat_loop )
85+ in
86+ let * () =
87+ Lwt. catch cat_loop (fun exn ->
88+ Logs. warn (fun m ->
89+ m "Error resolving file %s (%s)" fname (Printexc. to_string exn ));
90+ Lwt. return_unit )
91+ in
92+ Lwt. catch
93+ (fun () -> Lwt_io. close ic )
94+ (fun e ->
95+ Logs. warn (fun f ->
96+ f "Closing channel failed: %s" (Printexc. to_string e ));
97+ Lwt. return_unit )
98+ in
99+ let body = Body. make encoding stream in
100+ let mime_type = Magic_mime. lookup fname in
101+ let headers =
102+ Http.Header. add_opt_unless_exists headers "content-type" mime_type
103+ in
104+ Lwt. return (respond ~headers ~status ~encoding ~body () ))
105+ (function
106+ | Unix. Unix_error (Unix. ENOENT, _ , _ ) | Isnt_a_file ->
107+ Lwt. return (respond_not_found () )
108+ | exn -> Lwt. reraise exn )
109+
53110let update ?response ?body ?cookies {a_response; a_body; a_cookies} =
54111 let a_response =
55112 match response with Some response -> response | None -> a_response
0 commit comments