@@ -116,27 +116,101 @@ let find_static_page ~request ~usermode ~dir ~(err : Cohttp.Code.status)
116116 (Ocsigen_extensions. Error_in_user_config_file
117117 " Staticmod: cannot use '..' in user paths" )
118118
119+ (* Borrowed from TyXML:lib/xml_print.ml (and wrapped) to avoid the dependency *)
120+ let html_of_string s =
121+ let is_control c =
122+ let cc = Char. code c in
123+ cc < = 8 || cc = 11 || cc = 12 || (14 < = cc && cc < = 31 ) || cc = 127
124+ in
125+ let add_unsafe_char b = function
126+ | '<' -> Buffer. add_string b " <"
127+ | '>' -> Buffer. add_string b " >"
128+ | '"' -> Buffer. add_string b " ""
129+ | '&' -> Buffer. add_string b " &"
130+ | c when is_control c ->
131+ Buffer. add_string b " &#" ;
132+ Buffer. add_string b (string_of_int (Char. code c));
133+ Buffer. add_string b " ;"
134+ | c -> Buffer. add_char b c
135+ in
136+ let encode_unsafe_char s =
137+ let b = Buffer. create (String. length s) in
138+ String. iter (add_unsafe_char b) s;
139+ Buffer. contents b
140+ in
141+ encode_unsafe_char s
142+ (* End of borrowed code *)
143+
144+ let respond_dir relpath dname : (Cohttp.Response.t * Cohttp_lwt.Body.t) Lwt.t =
145+ let readsortdir =
146+ (* Read a complete directory and sort its entries *)
147+ let chunk_size = 1024 in
148+ let rec aux entries dir =
149+ Lwt_unix. readdir_n dir chunk_size >> = fun chunk ->
150+ let entries = chunk :: entries in
151+ if Array. length chunk < chunk_size
152+ then Lwt. return entries
153+ else aux entries dir
154+ in
155+ Lwt_unix. opendir dname >> = fun dir ->
156+ Lwt. finalize
157+ (fun () ->
158+ aux [] dir > |= fun entries ->
159+ List. sort compare (List. concat_map Array. to_list entries))
160+ (fun () -> Lwt_unix. closedir dir)
161+ in
162+ Lwt. catch
163+ (fun () ->
164+ readsortdir >> = fun entries ->
165+ let title = html_of_string (" Directory listing for /" ^ relpath) in
166+ let entries =
167+ List. filter_map
168+ (function
169+ | "." | ".." -> None
170+ | e ->
171+ Some
172+ (Printf. sprintf " <li><a href=\" %t\" >%t</a></li>"
173+ (fun () -> Ocsigen_lib.Url. encode ~plus: false e)
174+ (fun () -> html_of_string e)))
175+ entries
176+ in
177+ (* Chunks of [html (head (title x) []) (body [h1 [x]; ul y])] *)
178+ let chunk1 =
179+ {|<! DOCTYPE html>
180+ < html xmlns= " http://www.w3.org/1999/xhtml" >< head>< title> | }
181+ and chunk2 = {|</ title>< / head>< body>< h1> | }
182+ and chunk3 = {|</ h1>< ul> | }
183+ and chunkend = {|</ ul>< / body>< / html> | } in
184+ let doc =
185+ chunk1 :: title :: chunk2 :: title :: chunk3 :: (entries @ [chunkend])
186+ in
187+ let headers = Cohttp.Header. init_with " content-type" " text/html" in
188+ Lwt. return
189+ ( Cohttp.Response. make ~status: `OK ~headers ()
190+ , Cohttp_lwt.Body. of_string_list doc ))
191+ (function
192+ | Unix. Unix_error _ -> Cohttp_lwt_unix.Server. respond_not_found ()
193+ | exn -> Lwt. fail exn )
194+
119195let gen ~usermode ?cache dir = function
120196 | Ocsigen_extensions. Req_found _ ->
121197 Lwt. return Ocsigen_extensions. Ext_do_nothing
122198 | Ocsigen_extensions. Req_not_found
123199 (err, ({Ocsigen_extensions. request_info; _} as request)) ->
124200 let try_block () =
125201 Lwt_log. ign_info ~section " Is it a static file?" ;
202+ let pathstring =
203+ Ocsigen_lib.Url. string_of_url_path ~encode: false
204+ (Ocsigen_request. sub_path request_info)
205+ in
126206 let status_filter, page =
127- let pathstring =
128- Ocsigen_lib.Url. string_of_url_path ~encode: false
129- (Ocsigen_request. sub_path request_info)
130- in
131207 find_static_page ~request ~usermode ~dir ~err ~pathstring
132208 in
133- let fname =
134- match page with
135- | Ocsigen_local_files. RFile fname -> fname
136- | Ocsigen_local_files. RDir _ ->
137- failwith " FIXME: staticmod dirs not implemented"
138- in
139- Cohttp_lwt_unix.Server. respond_file ~fname () >> = fun answer ->
209+ (match page with
210+ | Ocsigen_local_files. RFile fname ->
211+ Cohttp_lwt_unix.Server. respond_file ~fname ()
212+ | Ocsigen_local_files. RDir dname -> respond_dir pathstring dname)
213+ >> = fun answer ->
140214 let answer = Ocsigen_response. of_cohttp answer in
141215 let answer =
142216 if not status_filter
0 commit comments