mirror of
https://github.com/c-cube/tiny_httpd.git
synced 2025-12-06 11:15:35 -05:00
add example for Writer.t response body
This commit is contained in:
parent
6137c20801
commit
355cc4d004
4 changed files with 96 additions and 0 deletions
26
README.md
26
README.md
|
|
@ -105,6 +105,32 @@ it allows downloading the files, and listing directories.
|
||||||
If a directory contains `index.html` then this will be served
|
If a directory contains `index.html` then this will be served
|
||||||
instead of listing the content.
|
instead of listing the content.
|
||||||
|
|
||||||
|
## Steaming response body
|
||||||
|
|
||||||
|
Tiny_httpd provides multiple ways of returning a body in a response.
|
||||||
|
The response body type is:
|
||||||
|
|
||||||
|
```ocaml
|
||||||
|
type body =
|
||||||
|
[ `String of string
|
||||||
|
| `Stream of byte_stream
|
||||||
|
| `Writer of Tiny_httpd_io.Writer.t
|
||||||
|
| `Void ]
|
||||||
|
```
|
||||||
|
|
||||||
|
The simplest way is to return, say, `` `String "hello" ``. The response
|
||||||
|
will have a set content-length header and its body is just the string.
|
||||||
|
Some responses don't have a body at all, which is where `` `Void `` is useful.
|
||||||
|
|
||||||
|
The `` `Stream _ `` case is more advanced and really only intended for experts.
|
||||||
|
|
||||||
|
The `` `Writer w `` is new, and is intended as an easy way to write the
|
||||||
|
body in a streaming fashion. See 'examples/writer.ml' to see a full example.
|
||||||
|
Typically the idea is to create the body with `Tiny_httpd_io.Writer.make ~write ()`
|
||||||
|
where `write` will be called with an output channel (the connection to the client),
|
||||||
|
and can write whatever it wants to this channel. Once the `write` function returns
|
||||||
|
the body has been fully sent and the next request can be processed.
|
||||||
|
|
||||||
## Socket activation
|
## Socket activation
|
||||||
|
|
||||||
Since version 0.10, socket activation is supported indirectly, by allowing a
|
Since version 0.10, socket activation is supported indirectly, by allowing a
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,12 @@
|
||||||
(libraries tiny_httpd tiny_httpd_camlzip
|
(libraries tiny_httpd tiny_httpd_camlzip
|
||||||
tiny_httpd_eio eio eio_posix))
|
tiny_httpd_eio eio eio_posix))
|
||||||
|
|
||||||
|
(executable
|
||||||
|
(name writer)
|
||||||
|
(flags :standard -warn-error -a+8)
|
||||||
|
(modules writer)
|
||||||
|
(libraries tiny_httpd))
|
||||||
|
|
||||||
(rule
|
(rule
|
||||||
(targets test_output.txt)
|
(targets test_output.txt)
|
||||||
(deps
|
(deps
|
||||||
|
|
|
||||||
62
examples/writer.ml
Normal file
62
examples/writer.ml
Normal file
|
|
@ -0,0 +1,62 @@
|
||||||
|
module H = Tiny_httpd
|
||||||
|
|
||||||
|
let serve_zeroes server : unit =
|
||||||
|
H.add_route_handler server H.(Route.(exact "zeroes" @/ int @/ return))
|
||||||
|
@@ fun n _req ->
|
||||||
|
(* stream [n] zeroes *)
|
||||||
|
let write (oc : H.IO.Out_channel.t) : unit =
|
||||||
|
let buf = Bytes.make 1 '0' in
|
||||||
|
for _i = 1 to n do
|
||||||
|
H.IO.Out_channel.output oc buf 0 1
|
||||||
|
done
|
||||||
|
in
|
||||||
|
let writer = H.IO.Writer.make ~write () in
|
||||||
|
H.Response.make_writer @@ Ok writer
|
||||||
|
|
||||||
|
let serve_file server : unit =
|
||||||
|
H.add_route_handler server H.(Route.(exact "file" @/ string @/ return))
|
||||||
|
@@ fun file _req ->
|
||||||
|
if Sys.file_exists file then (
|
||||||
|
(* stream the content of the file *)
|
||||||
|
let write oc =
|
||||||
|
let buf = Bytes.create 4096 in
|
||||||
|
let ic = open_in file in
|
||||||
|
Fun.protect ~finally:(fun () -> close_in_noerr ic) @@ fun () ->
|
||||||
|
while
|
||||||
|
let n = input ic buf 0 (Bytes.length buf) in
|
||||||
|
if n > 0 then H.IO.Out_channel.output oc buf 0 n;
|
||||||
|
n > 0
|
||||||
|
do
|
||||||
|
()
|
||||||
|
done
|
||||||
|
in
|
||||||
|
|
||||||
|
let writer = H.IO.Writer.make ~write () in
|
||||||
|
H.Response.make_writer @@ Ok writer
|
||||||
|
) else
|
||||||
|
H.Response.fail ~code:404 "file not found"
|
||||||
|
|
||||||
|
let () =
|
||||||
|
let port = ref 8085 in
|
||||||
|
Arg.parse [ "-p", Arg.Set_int port, " port" ] ignore "";
|
||||||
|
let server = H.create ~port:!port () in
|
||||||
|
Printf.printf "listen on http://localhost:%d/\n%!" !port;
|
||||||
|
serve_file server;
|
||||||
|
serve_zeroes server;
|
||||||
|
H.add_route_handler server H.Route.return (fun _req ->
|
||||||
|
let body =
|
||||||
|
H.Html.(
|
||||||
|
div []
|
||||||
|
[
|
||||||
|
p [] [ txt "routes" ];
|
||||||
|
ul []
|
||||||
|
[
|
||||||
|
li []
|
||||||
|
[ a [ A.href "/zeroes/1000" ] [ txt "get 1000 zeroes" ] ];
|
||||||
|
li [] [ a [ A.href "/file/f_13M" ] [ txt "read file" ] ];
|
||||||
|
];
|
||||||
|
])
|
||||||
|
|> H.Html.to_string_top
|
||||||
|
in
|
||||||
|
H.Response.make_string @@ Ok body);
|
||||||
|
H.run_exn server
|
||||||
2
writer.sh
Executable file
2
writer.sh
Executable file
|
|
@ -0,0 +1,2 @@
|
||||||
|
#!/bin/sh
|
||||||
|
exec dune exec --display=quiet -- examples/writer.exe $@
|
||||||
Loading…
Add table
Reference in a new issue