package paf
Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file paf_mirage.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 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383
module type S = sig type stack type ipaddr module TCP : sig include Mirage_flow.S val dst : flow -> ipaddr * int val no_close : flow -> unit val to_close : flow -> unit end module TLS : sig type error = [ `Tls_alert of Tls.Packet.alert_type | `Tls_failure of Tls.Engine.failure | `Read of TCP.error | `Write of TCP.write_error ] type write_error = [ `Closed | error ] include Mirage_flow.S with type error := error and type write_error := write_error val no_close : flow -> unit val to_close : flow -> unit val epoch : flow -> (Tls.Core.epoch_data, unit) result val reneg : ?authenticator:X509.Authenticator.t -> ?acceptable_cas:X509.Distinguished_name.t list -> ?cert:Tls.Config.own_cert -> ?drop:bool -> flow -> (unit, [ write_error | `Msg of string ]) result Lwt.t val key_update : ?request:bool -> flow -> (unit, [ write_error | `Msg of string ]) result Lwt.t val server_of_flow : Tls.Config.server -> TCP.flow -> (flow, write_error) result Lwt.t val client_of_flow : Tls.Config.client -> ?host:[ `host ] Domain_name.t -> TCP.flow -> (flow, write_error) result Lwt.t end val tcp_protocol : (stack * ipaddr * int, TCP.flow) Mimic.protocol val tcp_edn : (stack * ipaddr * int) Mimic.value val tls_edn : ([ `host ] Domain_name.t option * Tls.Config.client * stack * ipaddr * int) Mimic.value val tls_protocol : ( [ `host ] Domain_name.t option * Tls.Config.client * stack * ipaddr * int, TLS.flow ) Mimic.protocol type t type dst = ipaddr * int val init : port:int -> stack -> t Lwt.t val accept : t -> (TCP.flow, [> `Closed ]) result Lwt.t val close : t -> unit Lwt.t val http_service : ?config:H1.Config.t -> error_handler:(dst -> H1.Server_connection.error_handler) -> (TCP.flow -> dst -> H1.Server_connection.request_handler) -> t Paf.service val https_service : tls:Tls.Config.server -> ?config:H1.Config.t -> error_handler:(dst -> H1.Server_connection.error_handler) -> (TLS.flow -> dst -> H1.Server_connection.request_handler) -> t Paf.service val alpn_service : tls:Tls.Config.server -> ?config:H1.Config.t * H2.Config.t -> (TLS.flow, dst) Alpn.server_handler -> t Paf.service val serve : ?stop:Lwt_switch.t -> 't Paf.service -> 't -> [ `Initialized of unit Lwt.t ] end module Make (Stack : Tcpip.Tcp.S) : S with type stack = Stack.t and type ipaddr = Stack.ipaddr = struct open Lwt.Infix type ipaddr = Stack.ipaddr type dst = ipaddr * int module TCP = struct let src = Logs.Src.create "paf-tcp" module Log = (val Logs.src_log src : Logs.LOG) include Stack type nonrec flow = { flow : flow; mutable no_close : bool } type endpoint = Stack.t * Stack.ipaddr * int type nonrec write_error = [ `Write of write_error | `Connect of error | `Closed ] let pp_write_error ppf = function | `Write err | (`Closed as err) -> pp_write_error ppf err | `Connect err -> pp_error ppf err let read flow = read flow.flow let dst flow = dst flow.flow let write flow cs = write flow.flow cs >>= function | Ok _ as v -> Lwt.return v | Error err -> Lwt.return_error (`Write err) let writev flow css = writev flow.flow css >>= function | Ok _ as v -> Lwt.return v | Error err -> Lwt.return_error (`Write err) let connect (stack, ipaddr, port) = create_connection stack (ipaddr, port) >>= function | Ok flow -> Lwt.return_ok { flow; no_close = false } | Error err -> Lwt.return_error (`Connect err) let no_close flow = flow.no_close <- true let to_close flow = flow.no_close <- false let close flow = match flow.no_close with | true -> Log.debug (fun m -> m "Fakely close the connection.") ; Lwt.return_unit | false -> Log.debug (fun m -> m "Really close the connection.") ; close flow.flow let shutdown flow = shutdown flow.flow end module TLS = struct let src = Logs.Src.create "paf-tls" module Log = (val Logs.src_log src : Logs.LOG) include Tls_mirage.Make (TCP) type endpoint = [ `host ] Domain_name.t option * Tls.Config.client * Stack.t * Stack.ipaddr * int type nonrec flow = TCP.flow * flow let connect (host, cfg, stack, ipaddr, port) = Stack.create_connection stack (ipaddr, port) >>= function | Error err -> Lwt.return_error (`Read err) | Ok flow -> let open Lwt_result.Infix in let tcp_flow = { TCP.flow; TCP.no_close = false } in client_of_flow cfg ?host tcp_flow >>= fun tls_flow -> Lwt.return_ok (tcp_flow, tls_flow) let no_close (tcp_flow, _) = TCP.no_close tcp_flow let to_close (tcp_flow, _) = TCP.to_close tcp_flow let read (_, tls_flow) = read tls_flow let write (_, tls_flow) = write tls_flow let writev (_, tls_flow) = writev tls_flow let shutdown (_, tls_flow) = shutdown tls_flow let epoch (_, tls_flow) = epoch tls_flow let reneg ?authenticator ?acceptable_cas ?cert ?drop (_, tls_flow) = reneg ?authenticator ?acceptable_cas ?cert ?drop tls_flow let key_update ?request (_, tls_flow) = key_update ?request tls_flow let server_of_flow config tcp_flow = Lwt_result.Infix.( server_of_flow config tcp_flow >>= fun tls_flow -> Lwt.return_ok (tcp_flow, tls_flow)) let client_of_flow config ?host tcp_flow = Lwt_result.Infix.( client_of_flow config ?host tcp_flow >>= fun tls_flow -> Lwt.return_ok (tcp_flow, tls_flow)) let close (tcp_flow, tls_flow) = match tcp_flow.TCP.no_close with | true -> Lwt.return_unit | false -> close tls_flow end let src = Logs.Src.create "paf-layer" module Log = (val Logs.src_log src : Logs.LOG) type stack = Stack.t let tcp_edn, tcp_protocol = Mimic.register ~name:"tcp" (module TCP) let tls_edn, tls_protocol = Mimic.register ~priority:10 ~name:"tls" (module TLS) type t = { stack : Stack.t; queue : Stack.flow Queue.t; condition : unit Lwt_condition.t; mutex : Lwt_mutex.t; mutable closed : bool; } let init ~port stack = let queue = Queue.create () in let condition = Lwt_condition.create () in let mutex = Lwt_mutex.create () in let listener flow = Lwt_mutex.lock mutex >>= fun () -> Queue.push flow queue ; Lwt_condition.signal condition () ; Lwt_mutex.unlock mutex ; Lwt.return () in Stack.listen ~port stack listener ; Lwt.return { stack; queue; condition; mutex; closed = false } let rec accept ({ queue; condition; mutex; _ } as t) = Lwt_mutex.lock mutex >>= fun () -> let rec await () = if Queue.is_empty queue && not t.closed then Lwt_condition.wait condition ~mutex >>= await else Lwt.return_unit in await () >>= fun () -> match Queue.pop queue with | flow -> Lwt_mutex.unlock mutex ; Lwt.return_ok { TCP.flow; TCP.no_close = false } | exception Queue.Empty -> if t.closed then ( Lwt_mutex.unlock mutex ; Lwt.return_error `Closed) else ( Lwt_mutex.unlock mutex ; accept t) let close ({ condition; _ } as t) = t.closed <- true ; (* Stack.disconnect stack >>= fun () -> *) Lwt_condition.signal condition () ; Lwt.return_unit let http_service ?config ~error_handler request_handler = let module R = (val Mimic.repr tcp_protocol) in let connection flow = let dst = TCP.dst flow in let error_handler = error_handler dst in let request_handler' reqd = request_handler flow dst reqd in let conn = H1.Server_connection.create ?config ~error_handler request_handler' in Lwt.return_ok (R.T flow, Paf.Runtime ((module H1.Server_connection), conn)) in Paf.service connection Lwt.return_ok accept close let https_service ~tls ?config ~error_handler request_handler = let module R = (val Mimic.repr tls_protocol) in let handshake tcp_flow = let dst = TCP.dst tcp_flow in TLS.server_of_flow tls tcp_flow >>= function | Ok flow -> Lwt.return_ok (dst, flow) | Error `Closed -> (* XXX(dinosaure): be care! [`Closed] at this stage does not mean * that the bound socket is closed but the socket with the peer is * closed. *) Log.err (fun m -> m "The connection was closed by peer.") ; TCP.close tcp_flow >>= fun () -> Lwt.return_error `Closed | Error err -> Log.err (fun m -> m "Got a TLS error: %a." TLS.pp_write_error err) ; TCP.close tcp_flow >>= fun () -> Lwt.return_error err in let connection (dst, flow) = let error_handler = error_handler dst in let request_handler' reqd = request_handler flow dst reqd in let conn = H1.Server_connection.create ?config ~error_handler request_handler' in Lwt.return_ok (R.T flow, Paf.Runtime ((module H1.Server_connection), conn)) in Paf.service connection handshake accept close let alpn = let module R = (val Mimic.repr tls_protocol) in let alpn_of_tls_connection (_edn, flow) = match TLS.epoch flow with | Ok { Tls.Core.alpn_protocol; _ } -> alpn_protocol | Error _ -> None in let peer_of_tls_connection (edn, _flow) = edn in (* XXX(dinosaure): [TLS]/[ocaml-tls] should let us to project the underlying * [flow] and apply [TCP.dst] on it. * Actually, we did it with the [TLS] module. *) let injection (_edn, flow) = R.T flow in { Alpn.alpn = alpn_of_tls_connection; Alpn.peer = peer_of_tls_connection; Alpn.injection; } let alpn_service ~tls ?config:(_ = (H1.Config.default, H2.Config.default)) handler = let handshake tcp_flow = let dst = TCP.dst tcp_flow in TLS.server_of_flow tls tcp_flow >>= function | Ok flow -> Lwt.return_ok (dst, flow) | Error `Closed -> (* XXX(dinosaure): be care! [`Closed] at this stage does not mean * that the bound socket is closed but the socket with the peer is * closed. *) Log.err (fun m -> m "The connection was closed by peer.") ; Lwt.return_error (`Write `Closed) | Error err -> Log.err (fun m -> m "Got a TLS error: %a." TLS.pp_write_error err) ; TCP.close tcp_flow >>= fun () -> Lwt.return_error (err :> [ TLS.write_error | `Msg of string ]) in let module R = (val Mimic.repr tls_protocol) in let request flow edn reqd protocol = match flow with | R.T flow -> handler.Alpn.request flow edn reqd protocol | _ -> assert false (* XXX(dinosaure): this case should never occur. Indeed, the [injection] given to [Alpn.service] only create a [tls_protocol] flow. We just destruct it and give it to [request_handler]. *) in Alpn.service alpn { handler with request } handshake accept close let serve ?stop service t = Paf.serve ?stop service t end type transmission = [ `Clear | `TLS of string option ] let paf_transmission : transmission Mimic.value = Mimic.make ~name:"paf-transmission" let paf_endpoint : (Ipaddr.t * int) Mimic.value = Mimic.make ~name:"paf-endpoint" open Lwt.Infix let rec kind_of_flow : Mimic.edn list -> transmission option = function | Mimic.Edn (k, v) :: r -> ( match Mimic.equal k paf_transmission with | Some Mimic.Refl -> Some v | None -> kind_of_flow r) | [] -> None let rec endpoint_of_flow : Mimic.edn list -> (Ipaddr.t * int) option = function | Mimic.Edn (k, v) :: r -> ( match Mimic.equal k paf_endpoint with | Some Mimic.Refl -> Some v | None -> endpoint_of_flow r) | [] -> None let ( >>? ) = Lwt_result.bind let run ~ctx handler request = Mimic.unfold ctx >>? fun ress -> Mimic.connect ress >>= fun res -> match (res, kind_of_flow ress) with | (Error _ as err), _ -> Lwt.return err | Ok flow, (Some `Clear | None) -> let edn = endpoint_of_flow ress in let alpn = match request with `V1 _ -> "http/1.1" | `V2 _ -> "h2c" in Alpn.run ~alpn handler edn request flow | Ok flow, Some (`TLS alpn) -> let edn = endpoint_of_flow ress in Alpn.run ?alpn handler edn request flow
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>