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