package dream

  1. Overview
  2. Docs
Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source

Source file request_id.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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
(* This file is part of Dream, released under the MIT license. See LICENSE.md
   for details, or visit https://github.com/aantron/dream.

   Copyright 2021 Anton Bachin *)



(* TODO The other major built-in middleware, prefix, is actually just going to
   be built-in code. So it's probably best to look into building in request_id,
   and getting rid of the concept of built-in middleware. *)

module Dream = Dream__pure.Inmost



let name =
  "dream.request_id"

let last_id =
  Dream.new_global
    (fun () -> ref 0)
    ~name:"dream.request_id.last_id"
    ~show_value:(fun id -> string_of_int !id)

let id =
  Dream.new_local
    ()
    ~name
    ~show_value:(fun id -> id)

(* TODO Expose this in a more organized fashion? It is used in several
   places. *)
let lwt_key =
  Lwt.new_key ()



(* TODO Restore the prefix, make the id random, or something else. *)
(* TODO Now that the request id is built in, there is no good way for the user
   to pass in a prefix... except perhaps through the app. However, this is
   probably worth it, because adding request_id to every single middleware
   stack is extremely annoying, given that you always want it and it's so cheap
   that there is no reason not to use it. It's probably very rare that someone
   needs a prefix. *)
let assign_request_id next_handler request =

  (* Get the last id for this request's app. *)
  let last_id_ref : int ref =
    Dream.global last_id request in

  incr last_id_ref;

  let new_id =
    string_of_int !last_id_ref in

  (* Store the new id in the request and in the Lwt promise values map for
     best-effort delivery to all code that might want the id. Continue into the
     rest of the app. *)
  let request =
    Dream.with_local id new_id request in

  Lwt.with_value
    lwt_key
    (Some new_id)
    (fun () ->
      next_handler request)



let get_option ?request () =

  (* First, try to get the id from the request, if one was provided. *)
  let request_id =
    match request with
    | None -> None
    | Some request ->
      Dream.local id request
  in

  (* If no id was found from the maybe-request, look in the promise-chain-local
     storage. *)
  match request_id with
  | Some _ -> request_id
  | None ->
    Lwt.get lwt_key



(* TODO LATER Maybe it's better to build the request id straight into the
   runtime? There's no real cost to it... is there? And when wouldn't the user
   want a request id? *)
(* TODO LATER List arguments for built-in middlewares: 0 or so cost, highly
   beneficial, in some cases (prefix) actually necessary for correct operation
   of a website. *)
OCaml

Innovation. Community. Security.