module Record = Fastcgi_record (** Request-level state machine and application interface *) module Request = Fastcgi_request (* The lifetime of the handler is that the fiber should return when the stdout and stderr flows are closed, or an abort request has been received *) let handle req bw cancel fn = let cancel () = Eio.Promise.await cancel; Eio.traceln "cancelled TODO" in let stdout buf = Request.write_stdout_records bw req.Request.request_id buf in let stderr buf = Request.write_stderr_records bw req.Request.request_id buf in let run () = fn ~stdout ~stderr req; Request.write_end_request bw req.Request.request_id 0 Request.Request_complete in Eio.Fiber.first run cancel let run ?max_connections ?additional_domains ?stop ~on_error socket handler = Eio.Net.run_server socket ?max_connections ?additional_domains ?stop ~on_error (fun socket peer_address -> let ids = Hashtbl.create 7 in Eio.Switch.run @@ fun sw -> Eio.traceln "%a: accept connection" Eio.Net.Sockaddr.pp peer_address; let input = Eio.Buf_read.of_flow ~max_size:max_int socket in Eio.Buf_write.with_flow socket @@ fun output -> let cont = ref true in try while !cont do match Request.read_request input with | Error msg -> Eio.traceln "%a: failed to read request: %s" Eio.Net.Sockaddr.pp peer_address msg; failwith "done"; | Ok req -> cont := req.Request.keep_conn; Eio.traceln "%a: %b read request %a" Eio.Net.Sockaddr.pp peer_address !cont Request.pp req; Eio.Fiber.fork ~sw (fun () -> Eio.Switch.run ~name:"req_handler" @@ fun sw -> let cancel, canceler = Eio.Promise.create () in Hashtbl.add ids req.Request.request_id canceler; Eio.Switch.on_release sw (fun () -> Hashtbl.remove ids req.Request.request_id ); handle req output cancel handler; ); done with Eio.Io (Eio.Net.E (Connection_reset _), _) -> Eio.traceln "%a: connection reset" Eio.Net.Sockaddr.pp peer_address )