diff --git a/src/Tiny_httpd_io.ml b/src/Tiny_httpd_io.ml index 9503a903..b8db9ebe 100644 --- a/src/Tiny_httpd_io.ml +++ b/src/Tiny_httpd_io.ml @@ -56,6 +56,7 @@ end (** Output channel (byte sink) *) module Out_channel = struct type t = { + output_char: char -> unit; (** Output a single char *) output: bytes -> int -> int -> unit; (** Output slice *) flush: unit -> unit; (** Flush underlying buffer *) close: unit -> unit; (** Close the output. Must be idempotent. *) @@ -69,6 +70,7 @@ module Out_channel = struct instead of [close_out] to close [oc] *) let of_out_channel ?(close_noerr = false) (oc : out_channel) : t = { + output_char = (fun c -> output_char oc c); output = (fun buf i len -> output oc buf i len); flush = (fun () -> flush oc); close = @@ -82,7 +84,15 @@ module Out_channel = struct (** [of_buffer buf] is an output channel that writes directly into [buf]. [flush] and [close] have no effect. *) let of_buffer (buf : Buffer.t) : t = - { output = Buffer.add_subbytes buf; flush = ignore; close = ignore } + { + output_char = Buffer.add_char buf; + output = Buffer.add_subbytes buf; + flush = ignore; + close = ignore; + } + + (** Output the buffer slice into this channel *) + let[@inline] output_char (self : t) c : unit = self.output_char c (** Output the buffer slice into this channel *) let[@inline] output (self : t) buf i len : unit = self.output buf i len @@ -121,7 +131,14 @@ module Out_channel = struct output_string self "\r\n" ) in - { flush; close; output } + + (* terrible terrible. *) + let bchar = Bytes.create 1 in + let output_char c = + Bytes.set bchar 0 c; + output bchar 0 1 + in + { output_char; flush; close; output } end (** A writer abstraction. *) diff --git a/src/camlzip/Tiny_httpd_camlzip.ml b/src/camlzip/Tiny_httpd_camlzip.ml index 241577ce..5d3cbe6c 100644 --- a/src/camlzip/Tiny_httpd_camlzip.ml +++ b/src/camlzip/Tiny_httpd_camlzip.ml @@ -89,6 +89,13 @@ let encode_deflate_writer_ ~buf_size (w : W.t) : W.t = let write (oc : Out.t) : unit = let output buf i len = write_zlib ~flush:Zlib.Z_NO_FLUSH oc buf i len in + + let bchar = Bytes.create 1 in + let output_char c = + Bytes.set bchar 0 c; + output bchar 0 1 + in + let flush () = flush_zlib oc ~flush:Zlib.Z_FINISH; assert (!o_len = 0); @@ -100,7 +107,7 @@ let encode_deflate_writer_ ~buf_size (w : W.t) : W.t = oc.close () in (* new output channel that compresses on the fly *) - let oc' = { Out.flush; close; output } in + let oc' = { Out.flush; close; output; output_char } in w.write oc'; oc'.close () in diff --git a/src/eio/tiny_httpd_eio.ml b/src/eio/tiny_httpd_eio.ml index d8c89008..47bf3727 100644 --- a/src/eio/tiny_httpd_eio.ml +++ b/src/eio/tiny_httpd_eio.ml @@ -93,8 +93,16 @@ let oc_of_flow ~buf_pool:oc_pool (flow : Eio.Net.stream_socket) : if !offset = Bytes.length wbuf then flush () done in + + let output_char c = + if !offset = Bytes.length wbuf then flush (); + Bytes.set wbuf !offset c; + incr offset; + if !offset = Bytes.length wbuf then flush () + in + let close () = flow#shutdown `Send in - { IO.Out_channel.close; flush; output } + { IO.Out_channel.close; flush; output; output_char } let io_backend ?(addr = "127.0.0.1") ?(port = 8080) ?max_connections ~(stdenv : Eio_unix.Stdenv.base) ~(sw : Eio.Switch.t) () :