155 lines
5.2 KiB
OCaml
155 lines
5.2 KiB
OCaml
let set_interval s f destroy =
|
|
let rec set_interval_loop s f n =
|
|
let timeout =
|
|
Lwt_timeout.create s (fun () ->
|
|
if n > 0
|
|
then (if f () then set_interval_loop s f (n - 1))
|
|
else destroy ())
|
|
in
|
|
Lwt_timeout.start timeout
|
|
in
|
|
set_interval_loop s f 2
|
|
|
|
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.meth, request.target with
|
|
| `GET, "/" | `POST, "/" ->
|
|
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
|
|
Reqd.respond_with_string
|
|
request_descriptor
|
|
response
|
|
"non-empty data.")
|
|
~on_read:(fun _request_data ~off:_ ~len:_ -> respond ())
|
|
in
|
|
respond ()
|
|
| `POST, "/other" ->
|
|
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 response =
|
|
Response.create
|
|
~headers:(Headers.of_list [ "content-type", response_content_type ])
|
|
`OK
|
|
in
|
|
let response_body =
|
|
Reqd.respond_with_streaming request_descriptor response
|
|
in
|
|
let rec respond () =
|
|
Body.Reader.schedule_read
|
|
request_body
|
|
~on_eof:(fun () ->
|
|
set_interval
|
|
1
|
|
(fun () ->
|
|
Body.Writer.write_string response_body "FOO";
|
|
(* Body.flush response_body ignore; *)
|
|
true)
|
|
(* Body.flush response_body ignore; *)
|
|
(fun () -> Body.Writer.close response_body))
|
|
~on_read:(fun request_data ~off ~len ->
|
|
Body.Writer.write_bigstring response_body request_data ~off ~len;
|
|
respond ())
|
|
in
|
|
respond ()
|
|
| `POST, "/foo" ->
|
|
let response =
|
|
Response.create
|
|
`OK
|
|
~headers:(Headers.of_list [ "content-type", "text/event-stream" ])
|
|
in
|
|
let request_body = Reqd.request_body request_descriptor in
|
|
let response_body =
|
|
Reqd.respond_with_streaming request_descriptor response
|
|
in
|
|
(* let (finished, notify) = Lwt.wait () in *)
|
|
let rec on_read _request_data ~off:_ ~len:_ =
|
|
Body.Writer.flush response_body (fun _ ->
|
|
Body.Reader.schedule_read request_body ~on_eof ~on_read)
|
|
and on_eof () =
|
|
set_interval
|
|
2
|
|
(fun () ->
|
|
let _ =
|
|
Body.Writer.write_string response_body "data: some data\n\n"
|
|
in
|
|
Body.Writer.flush response_body ignore;
|
|
true)
|
|
(fun () ->
|
|
let _ =
|
|
Body.Writer.write_string response_body "event: end\ndata: 1\n\n"
|
|
in
|
|
Body.Writer.flush response_body (fun _ ->
|
|
Body.Writer.close response_body))
|
|
in
|
|
Body.Reader.schedule_read ~on_read ~on_eof request_body;
|
|
()
|
|
| _ ->
|
|
Reqd.respond_with_string
|
|
request_descriptor
|
|
(Response.create `Method_not_allowed)
|
|
"Hello, Sean."
|
|
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:None
|
|
~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 "Listening on port %i and echoing POST requests.\n" !port;
|
|
print_string "To send a POST request, try\n\n";
|
|
print_string " echo foo | dune exec examples/lwt/lwt_post.exe\n\n";
|
|
flush stdout;
|
|
Lwt.return_unit);
|
|
let forever, _ = Lwt.wait () in
|
|
Lwt_main.run forever
|