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
module Formats = Dream_pure.Formats
module Message = Dream_pure.Message
module Method = Dream_pure.Method
module Router = Dream__server.Router
module Stream = Dream_pure.Stream
let mime_lookup filename =
let content_type =
match Magic_mime.lookup filename with
| "text/html" -> Formats.text_html
| content_type -> content_type
in
["Content-Type", content_type]
let from_filesystem local_root path _ =
let file = Filename.concat local_root path in
Lwt.catch
(fun () ->
Lwt_io.(with_file ~mode:Input file) (fun channel ->
let%lwt content = Lwt_io.read channel in
Message.response
~headers:(mime_lookup path) (Stream.string content) Stream.null
|> Lwt.return))
(fun _exn ->
Message.response ~status:`Not_Found Stream.empty Stream.null
|> Lwt.return)
let validate_path request =
let path = Router.path request in
let has_slash component = String.contains component '/' in
let has_backslash component = String.contains component '\\' in
let has_slash = List.exists has_slash path in
let has_backslash = List.exists has_backslash path in
let has_dot = List.exists ((=) Filename.current_dir_name) path in
let has_dotdot = List.exists ((=) Filename.parent_dir_name) path in
let has_empty = List.exists ((=) "") path in
let is_empty = path = [] in
if has_slash ||
has_backslash ||
has_dot ||
has_dotdot ||
has_empty ||
is_empty then
None
else
let path = String.concat Filename.dir_sep path in
if Filename.is_relative path then
Some path
else
None
let static ?(loader = from_filesystem) local_root = fun request ->
if not @@ Method.methods_equal (Message.method_ request) `GET then
Message.response ~status:`Not_Found Stream.empty Stream.null
|> Lwt.return
else
match validate_path request with
| None ->
Message.response ~status:`Not_Found Stream.empty Stream.null
|> Lwt.return
| Some path ->
let%lwt response = loader local_root path request in
if not (Message.has_header response "Content-Type") then begin
match Message.status response with
| `OK
| `Non_Authoritative_Information
| `No_Content
| `Reset_Content
| `Partial_Content ->
Message.add_header response "Content-Type" (Magic_mime.lookup path)
| _ ->
()
end;
Lwt.return response