mirror of
https://github.com/c-cube/tiny_httpd.git
synced 2025-12-07 03:35:34 -05:00
wip: tiny_httpd_eio, an alternative IO/concurrency backend based on Eio
This commit is contained in:
parent
80ed51576b
commit
e00c3a5d63
4 changed files with 185 additions and 0 deletions
8
src/eio/dune
Normal file
8
src/eio/dune
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
|
||||||
|
(library
|
||||||
|
(name tiny_httpd_eio)
|
||||||
|
(public_name tiny_httpd_eio)
|
||||||
|
(synopsis "An EIO-based backend for Tiny_httpd")
|
||||||
|
(flags :standard -safe-string -warn-error -a+8)
|
||||||
|
(libraries tiny_httpd eio))
|
||||||
|
|
||||||
134
src/eio/tiny_httpd_eio.ml
Normal file
134
src/eio/tiny_httpd_eio.ml
Normal file
|
|
@ -0,0 +1,134 @@
|
||||||
|
module IO = Tiny_httpd_io
|
||||||
|
module H = Tiny_httpd_server
|
||||||
|
|
||||||
|
let ( let@ ) = ( @@ )
|
||||||
|
|
||||||
|
type 'a with_args =
|
||||||
|
?addr:string ->
|
||||||
|
?port:int ->
|
||||||
|
?max_connections:int ->
|
||||||
|
stdenv:Eio.Stdenv.t ->
|
||||||
|
sw:Eio.Switch.t ->
|
||||||
|
'a
|
||||||
|
|
||||||
|
let get_max_connection_ ?(max_connections = 64) () : int =
|
||||||
|
let max_connections = max 4 max_connections in
|
||||||
|
max_connections
|
||||||
|
|
||||||
|
let read_buf_size = 4 * 1024
|
||||||
|
let write_buf_size = 8 * 1024
|
||||||
|
|
||||||
|
let ic_of_flow (flow : Eio.Net.stream_socket) : IO.In_channel.t =
|
||||||
|
let cstruct = Cstruct.create write_buf_size in
|
||||||
|
let input buf i len =
|
||||||
|
if len = 0 then
|
||||||
|
0
|
||||||
|
else (
|
||||||
|
let n = flow#read_into (Cstruct.sub cstruct 0 (min len write_buf_size)) in
|
||||||
|
Cstruct.blit_to_bytes cstruct 0 buf i n;
|
||||||
|
n
|
||||||
|
)
|
||||||
|
in
|
||||||
|
let close () = flow#shutdown `Receive in
|
||||||
|
{ IO.In_channel.input; close }
|
||||||
|
|
||||||
|
let oc_of_flow (flow : Eio.Net.stream_socket) : IO.Out_channel.t =
|
||||||
|
let output buf i len =
|
||||||
|
if len > 0 then (
|
||||||
|
let i = ref i in
|
||||||
|
let len = ref len in
|
||||||
|
|
||||||
|
let src =
|
||||||
|
object
|
||||||
|
inherit Eio.Flow.source
|
||||||
|
|
||||||
|
method read_into (cstruct : Cstruct.t) : int =
|
||||||
|
if !len = 0 then raise End_of_file;
|
||||||
|
let n = min !len (Cstruct.length cstruct) in
|
||||||
|
Cstruct.blit_from_bytes buf !i cstruct 0 n;
|
||||||
|
i := !i + n;
|
||||||
|
len := !len - n;
|
||||||
|
n
|
||||||
|
end
|
||||||
|
in
|
||||||
|
|
||||||
|
flow#copy src
|
||||||
|
)
|
||||||
|
in
|
||||||
|
let close () = flow#shutdown `Send in
|
||||||
|
let flush () = () in
|
||||||
|
{ IO.Out_channel.close; flush; output }
|
||||||
|
|
||||||
|
let io_backend ?(addr = "127.0.0.1") ?(port = 8080) ?max_connections
|
||||||
|
~(stdenv : Eio.Stdenv.t) ~(sw : Eio.Switch.t) () : (module H.IO_BACKEND) =
|
||||||
|
let module M = struct
|
||||||
|
let init_addr () = addr
|
||||||
|
let init_port () = port
|
||||||
|
|
||||||
|
let get_time_s () =
|
||||||
|
let clock = Eio.Stdenv.clock stdenv in
|
||||||
|
Eio.Time.now clock
|
||||||
|
|
||||||
|
let spawn f : unit =
|
||||||
|
Eio.Switch.run @@ fun sub_sw -> Eio.Fiber.fork ~sw:sub_sw f
|
||||||
|
|
||||||
|
let tcp_server () : IO.TCP_server.builder =
|
||||||
|
{
|
||||||
|
IO.TCP_server.serve =
|
||||||
|
(fun ~after_init ~handle () : unit ->
|
||||||
|
let ip_addr = Eio.Net.Ipaddr.V4.any in
|
||||||
|
let running = Atomic.make true in
|
||||||
|
let active_conns = Atomic.make 0 in
|
||||||
|
|
||||||
|
Eio.Switch.on_release sw (fun () -> Atomic.set running false);
|
||||||
|
let net = Eio.Stdenv.net stdenv in
|
||||||
|
|
||||||
|
(* main server socket *)
|
||||||
|
let sock =
|
||||||
|
let backlog = get_max_connection_ ?max_connections () in
|
||||||
|
Eio.Net.listen ~reuse_addr:true ~reuse_port:true ~backlog ~sw net
|
||||||
|
(`Tcp (ip_addr, port))
|
||||||
|
in
|
||||||
|
|
||||||
|
let tcp_server : IO.TCP_server.t =
|
||||||
|
{
|
||||||
|
running = (fun () -> Atomic.get running);
|
||||||
|
stop = (fun () -> Atomic.set running false);
|
||||||
|
endpoint =
|
||||||
|
(fun () ->
|
||||||
|
(* TODO: find the real port *)
|
||||||
|
addr, port);
|
||||||
|
active_connections = (fun () -> Atomic.get active_conns);
|
||||||
|
}
|
||||||
|
in
|
||||||
|
|
||||||
|
after_init tcp_server;
|
||||||
|
|
||||||
|
while Atomic.get running do
|
||||||
|
Eio.Switch.check sw;
|
||||||
|
|
||||||
|
Eio.Net.accept_fork ~sw
|
||||||
|
~on_error:(fun exn ->
|
||||||
|
H._debug (fun k ->
|
||||||
|
k "error in client handler: %s" (Printexc.to_string exn)))
|
||||||
|
sock
|
||||||
|
(fun flow _client_addr ->
|
||||||
|
Atomic.incr active_conns;
|
||||||
|
let@ () =
|
||||||
|
Fun.protect ~finally:(fun () ->
|
||||||
|
H._debug (fun k ->
|
||||||
|
k "Tiny_httpd_eio: client handler returned");
|
||||||
|
Atomic.decr active_conns)
|
||||||
|
in
|
||||||
|
let ic = ic_of_flow flow in
|
||||||
|
let oc = oc_of_flow flow in
|
||||||
|
handle.handle ic oc)
|
||||||
|
done);
|
||||||
|
}
|
||||||
|
end in
|
||||||
|
(module M)
|
||||||
|
|
||||||
|
let create ?addr ?port ?max_connections ~stdenv ~sw ?buf_size ?middlewares () :
|
||||||
|
H.t =
|
||||||
|
let backend = io_backend ?addr ?port ?max_connections ~stdenv ~sw () in
|
||||||
|
H.create_from ?buf_size ?middlewares ~backend ()
|
||||||
21
src/eio/tiny_httpd_eio.mli
Normal file
21
src/eio/tiny_httpd_eio.mli
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
(* TODO: pass in a switch *)
|
||||||
|
|
||||||
|
type 'a with_args =
|
||||||
|
?addr:string ->
|
||||||
|
?port:int ->
|
||||||
|
?max_connections:int ->
|
||||||
|
stdenv:Eio.Stdenv.t ->
|
||||||
|
sw:Eio.Switch.t ->
|
||||||
|
'a
|
||||||
|
|
||||||
|
val io_backend : (unit -> (module Tiny_httpd_server.IO_BACKEND)) with_args
|
||||||
|
(** Create a server *)
|
||||||
|
|
||||||
|
val create :
|
||||||
|
(?buf_size:int ->
|
||||||
|
?middlewares:
|
||||||
|
([ `Encoding | `Stage of int ] * Tiny_httpd_server.Middleware.t) list ->
|
||||||
|
unit ->
|
||||||
|
Tiny_httpd_server.t)
|
||||||
|
with_args
|
||||||
|
(** Create a server *)
|
||||||
22
tiny_httpd_eio.opam
Normal file
22
tiny_httpd_eio.opam
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
opam-version: "2.0"
|
||||||
|
version: "0.13"
|
||||||
|
authors: ["Simon Cruanes"]
|
||||||
|
maintainer: "simon.cruanes.2007@m4x.org"
|
||||||
|
license: "MIT"
|
||||||
|
synopsis: "Run tiny_httpd on Eio"
|
||||||
|
build: [
|
||||||
|
["dune" "build" "@install" "-p" name "-j" jobs]
|
||||||
|
["dune" "build" "@doc" "-p" name] {with-doc}
|
||||||
|
["dune" "runtest" "-p" name] {with-test}
|
||||||
|
]
|
||||||
|
depends: [
|
||||||
|
"dune" { >= "2.0" }
|
||||||
|
"eio" {>= "0.9"}
|
||||||
|
"tiny_httpd" { = version }
|
||||||
|
"odoc" {with-doc}
|
||||||
|
]
|
||||||
|
tags: [ "http" "server" "eio" ]
|
||||||
|
homepage: "https://github.com/c-cube/tiny_httpd/"
|
||||||
|
doc: "https://c-cube.github.io/tiny_httpd/"
|
||||||
|
bug-reports: "https://github.com/c-cube/tiny_httpd/issues"
|
||||||
|
dev-repo: "git+https://github.com/c-cube/tiny_httpd.git"
|
||||||
Loading…
Add table
Reference in a new issue