116 lines
4.1 KiB
OCaml
116 lines
4.1 KiB
OCaml
|
|
let set_interval s f =
|
||
|
|
let timeout = Lwt_timeout.create s f in
|
||
|
|
Lwt_timeout.start timeout
|
||
|
|
|
||
|
|
let connection_handler : Unix.sockaddr -> Lwt_unix.file_descr -> unit Lwt.t =
|
||
|
|
let open H2 in
|
||
|
|
let request_handler : Unix.sockaddr -> Reqd.t -> unit =
|
||
|
|
fun _client_address request_descriptor ->
|
||
|
|
let request = Reqd.request request_descriptor in
|
||
|
|
match request.target with
|
||
|
|
(* This set of routes responds immediately without reading the request
|
||
|
|
body *)
|
||
|
|
| "/immediately" ->
|
||
|
|
let response_content_type =
|
||
|
|
match Headers.get request.headers "content-type" with
|
||
|
|
| Some request_content_type -> request_content_type
|
||
|
|
| None -> "application/octet-stream"
|
||
|
|
in
|
||
|
|
let request_body = Reqd.request_body request_descriptor in
|
||
|
|
Body.Reader.close request_body;
|
||
|
|
let response =
|
||
|
|
Response.create
|
||
|
|
~headers:(Headers.of_list [ "content-type", response_content_type ])
|
||
|
|
`OK
|
||
|
|
in
|
||
|
|
Reqd.respond_with_string request_descriptor response "non-empty data."
|
||
|
|
| _ ->
|
||
|
|
(* This set of routes waits until the entire request body has been read
|
||
|
|
* to produce a response. *)
|
||
|
|
let request_body = Reqd.request_body request_descriptor in
|
||
|
|
let response_content_type =
|
||
|
|
match Headers.get request.headers "content-type" with
|
||
|
|
| Some request_content_type -> request_content_type
|
||
|
|
| None -> "application/octet-stream"
|
||
|
|
in
|
||
|
|
let rec respond () =
|
||
|
|
Body.Reader.schedule_read
|
||
|
|
request_body
|
||
|
|
~on_eof:(fun () ->
|
||
|
|
let response =
|
||
|
|
Response.create
|
||
|
|
~headers:
|
||
|
|
(Headers.of_list [ "content-type", response_content_type ])
|
||
|
|
`OK
|
||
|
|
in
|
||
|
|
match request.target with
|
||
|
|
| "/streaming" ->
|
||
|
|
let response_body =
|
||
|
|
Reqd.respond_with_streaming request_descriptor response
|
||
|
|
in
|
||
|
|
Body.Writer.write_string response_body (String.make 100 'a');
|
||
|
|
set_interval 1 (fun () ->
|
||
|
|
ignore
|
||
|
|
@@ Reqd.try_with request_descriptor (fun () ->
|
||
|
|
Body.Writer.write_string response_body " data");
|
||
|
|
Body.Writer.flush response_body (fun _reason ->
|
||
|
|
Body.Writer.close response_body))
|
||
|
|
| "/bigstring" ->
|
||
|
|
let res_body = "non-empty data." in
|
||
|
|
let bs =
|
||
|
|
Bigstringaf.of_string
|
||
|
|
~off:0
|
||
|
|
~len:(String.length res_body)
|
||
|
|
res_body
|
||
|
|
in
|
||
|
|
Reqd.respond_with_bigstring request_descriptor response bs
|
||
|
|
| "/string" | _ ->
|
||
|
|
Reqd.respond_with_string
|
||
|
|
request_descriptor
|
||
|
|
response
|
||
|
|
"non-empty data.")
|
||
|
|
~on_read:(fun _request_data ~off:_ ~len:_ -> respond ())
|
||
|
|
in
|
||
|
|
respond ()
|
||
|
|
in
|
||
|
|
let error_handler :
|
||
|
|
Unix.sockaddr
|
||
|
|
-> ?request:H2.Request.t
|
||
|
|
-> _
|
||
|
|
-> (Headers.t -> Body.Writer.t)
|
||
|
|
-> unit
|
||
|
|
=
|
||
|
|
fun _client_address ?request:_ error start_response ->
|
||
|
|
let response_body = start_response Headers.empty in
|
||
|
|
(match error with
|
||
|
|
| `Exn exn ->
|
||
|
|
Body.Writer.write_string response_body (Printexc.to_string exn);
|
||
|
|
Body.Writer.write_string response_body "\n"
|
||
|
|
| #Status.standard as error ->
|
||
|
|
Body.Writer.write_string
|
||
|
|
response_body
|
||
|
|
(Status.default_reason_phrase error));
|
||
|
|
Body.Writer.close response_body
|
||
|
|
in
|
||
|
|
H2_lwt_unix.Server.create_connection_handler
|
||
|
|
~config:{ H2.Config.default with max_concurrent_streams = 2l }
|
||
|
|
~request_handler
|
||
|
|
~error_handler
|
||
|
|
|
||
|
|
let () =
|
||
|
|
let open Lwt.Infix in
|
||
|
|
Sys.(set_signal sigpipe Signal_ignore);
|
||
|
|
let port = ref 8080 in
|
||
|
|
Arg.parse
|
||
|
|
[ "-p", Arg.Set_int port, " Listening port number (8080 by default)" ]
|
||
|
|
ignore
|
||
|
|
"Echoes POST requests. Runs forever.";
|
||
|
|
let listen_address = Unix.(ADDR_INET (inet_addr_loopback, !port)) in
|
||
|
|
Lwt.async (fun () ->
|
||
|
|
Lwt_io.establish_server_with_client_socket listen_address connection_handler
|
||
|
|
>>= fun _server ->
|
||
|
|
Printf.printf "Server listening on port %i\n%!" !port;
|
||
|
|
Lwt.return_unit);
|
||
|
|
let forever, _ = Lwt.wait () in
|
||
|
|
Lwt_main.run forever
|