package sihl

  1. Overview
  2. Docs
The modular functional web framework

Install

Dune Dependency

Authors

Maintainers

Sources

sihl-queue-0.1.5.tbz
sha256=bfa7bde9af02bb83d5ca39d54797b05b43317f033d93d24ca86ca42ff8ef83a1
sha512=6bb8727f65116e8042aa1fb77b3c14851ce5238f7b412adadf0f8e5b52d5310e8f06056c96bf76a82ffd7096753f49b2b0482f41e18ee1ca94310b874fe81bf9

doc/src/sihl.middleware/middleware_static.ml.html

Source file middleware_static.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
open Opium_kernel__Misc
open Sexplib.Std
module Server = Cohttp_lwt_unix.Server
open Opium_kernel.Rock

type t =
  { prefix : string
  ; local_path : string
  }
[@@deriving fields, sexp]

let legal_path { prefix; local_path } requested =
  let p = String.chop_prefix requested ~prefix in
  let requested_path = Filename.concat local_path p in
  if String.is_prefix requested_path ~prefix:local_path then Some requested_path else None
;;

let public_serve t ~requested ~request_if_none_match ?etag_of_fname ?headers () =
  match legal_path t requested with
  | None -> return `Not_found
  | Some legal_path ->
    let etag_quoted =
      match etag_of_fname with
      | Some f -> Some (Printf.sprintf "%S" (f legal_path))
      | None -> None
    in
    let mime_type = Magic_mime.lookup legal_path in
    let headers = Cohttp.Header.add_opt_unless_exists headers "content-type" mime_type in
    let headers =
      match etag_quoted with
      | Some etag_quoted -> Cohttp.Header.add_unless_exists headers "etag" etag_quoted
      | None -> headers
    in
    let request_matches_etag =
      match request_if_none_match, etag_quoted with
      | Some request_etags, Some etag_quoted ->
        request_etags
        |> Stringext.split ~on:','
        |> List.exists ~f:(fun request_etag -> String.trim request_etag = etag_quoted)
      | _ -> false
    in
    if request_matches_etag
    then `Ok (Response.create ~code:`Not_modified ~headers ()) |> Lwt.return
    else
      Server.respond_file ~headers ~fname:legal_path ()
      >>| fun resp ->
      if resp |> fst |> Cohttp.Response.status = `Not_found
      then `Not_found
      else `Ok (Response.of_response_body resp)
;;

let m ~local_path_f ~uri_prefix_f ?headers ?etag_of_fname () =
  let filter handler ctx =
    let local_path = local_path_f () in
    let uri_prefix = uri_prefix_f () in
    if Http.Req.is_get ctx
    then (
      let local_map = { prefix = uri_prefix; local_path } in
      let local_path = ctx |> Http.Req.get_uri |> Uri.path in
      if local_path |> String.is_prefix ~prefix:uri_prefix
      then (
        let request_if_none_match = Http.Req.get_header ctx "If-None-Match" in
        public_serve
          local_map
          ~requested:local_path
          ~request_if_none_match
          ?etag_of_fname
          ?headers
          ()
        >>= function
        | `Not_found -> handler ctx
        | `Ok x -> return Http.Res.(html |> set_opium_res x))
      else handler ctx)
    else handler ctx
  in
  Middleware_core.create ~name:"static" filter
;;
OCaml

Innovation. Community. Security.