@@ -116,27 +116,101 @@ let find_static_page ~request ~usermode ~dir ~(err : Cohttp.Code.status)
116
116
(Ocsigen_extensions. Error_in_user_config_file
117
117
" Staticmod: cannot use '..' in user paths" )
118
118
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
+
119
195
let gen ~usermode ?cache dir = function
120
196
| Ocsigen_extensions. Req_found _ ->
121
197
Lwt. return Ocsigen_extensions. Ext_do_nothing
122
198
| Ocsigen_extensions. Req_not_found
123
199
(err, ({Ocsigen_extensions. request_info; _} as request)) ->
124
200
let try_block () =
125
201
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
126
206
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
131
207
find_static_page ~request ~usermode ~dir ~err ~pathstring
132
208
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 ->
140
214
let answer = Ocsigen_response. of_cohttp answer in
141
215
let answer =
142
216
if not status_filter
0 commit comments