add optional dependency on logs

This commit is contained in:
Simon Cruanes 2024-01-23 16:00:52 -05:00
parent 5d6edb51e9
commit 86f1b9025d
No known key found for this signature in database
GPG key ID: EBFFF6F283F3A2B4
16 changed files with 106 additions and 73 deletions

View file

@ -14,6 +14,7 @@
(synopsis "Minimal HTTP server using threads") (synopsis "Minimal HTTP server using threads")
(tags (http thread server tiny_httpd http_of_dir simplehttpserver)) (tags (http thread server tiny_httpd http_of_dir simplehttpserver))
(depopts (depopts
logs
(mtime (>= 2.0))) (mtime (>= 2.0)))
(depends (depends
seq seq

View file

@ -1,7 +1,7 @@
(executable (executable
(name sse_server) (name sse_server)
(modules sse_server) (modules sse_server)
(libraries tiny_httpd unix ptime ptime.clock.os)) (libraries tiny_httpd logs unix ptime ptime.clock.os))
(executable (executable
(name sse_client) (name sse_client)
@ -12,13 +12,13 @@
(name echo) (name echo)
(flags :standard -warn-error -a+8) (flags :standard -warn-error -a+8)
(modules echo vfs) (modules echo vfs)
(libraries tiny_httpd tiny_httpd_camlzip)) (libraries tiny_httpd logs tiny_httpd_camlzip))
(executable (executable
(name writer) (name writer)
(flags :standard -warn-error -a+8) (flags :standard -warn-error -a+8)
(modules writer) (modules writer)
(libraries tiny_httpd)) (libraries tiny_httpd logs))
(rule (rule
(targets test_output.txt) (targets test_output.txt)

View file

@ -1,4 +1,5 @@
module S = Tiny_httpd module S = Tiny_httpd
module Log = Tiny_httpd.Log
let now_ = Unix.gettimeofday let now_ = Unix.gettimeofday
@ -73,6 +74,10 @@ let base64 x =
ignore (Unix.close_process (ic, oc)); ignore (Unix.close_process (ic, oc));
r r
let setup_logging () =
Logs.set_reporter @@ Logs.format_reporter ();
Logs.set_level ~all:true (Some Logs.Debug)
let () = let () =
let port_ = ref 8080 in let port_ = ref 8080 in
let j = ref 32 in let j = ref 32 in
@ -81,7 +86,7 @@ let () =
[ [
"--port", Arg.Set_int port_, " set port"; "--port", Arg.Set_int port_, " set port";
"-p", Arg.Set_int port_, " set port"; "-p", Arg.Set_int port_, " set port";
"--debug", Arg.Unit (fun () -> S._enable_debug true), " enable debug"; "--debug", Arg.Unit setup_logging, " enable debug";
"-j", Arg.Set_int j, " maximum number of connections"; "-j", Arg.Set_int j, " maximum number of connections";
]) ])
(fun _ -> raise (Arg.Bad "")) (fun _ -> raise (Arg.Bad ""))
@ -134,7 +139,7 @@ let () =
S.add_route_handler_stream ~meth:`PUT server S.add_route_handler_stream ~meth:`PUT server
S.Route.(exact "upload" @/ string @/ return) S.Route.(exact "upload" @/ string @/ return)
(fun path req -> (fun path req ->
S._debug (fun k -> Log.debug (fun k ->
k "start upload %S, headers:\n%s\n\n%!" path k "start upload %S, headers:\n%s\n\n%!" path
(Format.asprintf "%a" S.Headers.pp (S.Request.headers req))); (Format.asprintf "%a" S.Headers.pp (S.Request.headers req)));
try try
@ -153,7 +158,7 @@ let () =
let ok = let ok =
match S.Request.get_header req "authorization" with match S.Request.get_header req "authorization" with
| Some v -> | Some v ->
S._debug (fun k -> k "authenticate with %S" v); Log.debug (fun k -> k "authenticate with %S" v);
v = "Basic " ^ base64 "user:foobar" v = "Basic " ^ base64 "user:foobar"
| None -> false | None -> false
in in

View file

@ -1,6 +1,7 @@
(* serves some streams of events *) (* serves some streams of events *)
module S = Tiny_httpd module S = Tiny_httpd
module Log = Tiny_httpd_log
let port = ref 8080 let port = ref 8080
@ -9,7 +10,7 @@ let () =
(Arg.align (Arg.align
[ [
"-p", Arg.Set_int port, " port to listen on"; "-p", Arg.Set_int port, " port to listen on";
"--debug", Arg.Bool S._enable_debug, " toggle debug"; "--debug", Arg.Unit (Log.setup ~debug:true), " enable debug";
]) ])
(fun _ -> ()) (fun _ -> ())
"sse_clock [opt*]"; "sse_clock [opt*]";
@ -26,12 +27,12 @@ let () =
S.add_route_server_sent_handler server S.add_route_server_sent_handler server
S.Route.(exact "clock" @/ return) S.Route.(exact "clock" @/ return)
(fun _req (module EV : S.SERVER_SENT_GENERATOR) -> (fun _req (module EV : S.SERVER_SENT_GENERATOR) ->
S._debug (fun k -> k "new connection"); Log.debug (fun k -> k "new SSE connection");
EV.set_headers extra_headers; EV.set_headers extra_headers;
let tick = ref true in let tick = ref true in
while true do while true do
let now = Ptime_clock.now () in let now = Ptime_clock.now () in
S._debug (fun k -> Log.debug (fun k ->
k "send clock ev %s" (Format.asprintf "%a" Ptime.pp now)); k "send clock ev %s" (Format.asprintf "%a" Ptime.pp now));
EV.send_event EV.send_event
~event: ~event:

View file

@ -6,3 +6,4 @@ module Dir = Tiny_httpd_dir
module Html = Tiny_httpd_html module Html = Tiny_httpd_html
module IO = Tiny_httpd_io module IO = Tiny_httpd_io
module Pool = Tiny_httpd_pool module Pool = Tiny_httpd_pool
module Log = Tiny_httpd_log

View file

@ -89,6 +89,10 @@ module Byte_stream = Tiny_httpd_stream
module IO = Tiny_httpd_io module IO = Tiny_httpd_io
(** {2 Logging *)
module Log = Tiny_httpd_log
(** {2 Main Server Type} *) (** {2 Main Server Type} *)
(** @inline *) (** @inline *)

View file

@ -1,6 +1,7 @@
module S = Tiny_httpd_server module S = Tiny_httpd_server
module U = Tiny_httpd_util module U = Tiny_httpd_util
module Html = Tiny_httpd_html module Html = Tiny_httpd_html
module Log = Tiny_httpd_log
type dir_behavior = Index | Lists | Index_or_lists | Forbidden type dir_behavior = Index | Lists | Index_or_lists | Forbidden
type hidden = unit type hidden = unit
@ -250,7 +251,7 @@ let add_vfs_ ~on_fs ~top ~config ~vfs:((module VFS : VFS) as vfs) ~prefix server
in in
Tiny_httpd_stream.iter write req.S.Request.body; Tiny_httpd_stream.iter write req.S.Request.body;
close (); close ();
S._debug (fun k -> k "done uploading"); Log.debug (fun k -> k "dir: done uploading file to %S" path);
S.Response.make_raw ~code:201 "upload successful") S.Response.make_raw ~code:201 "upload successful")
else else
S.add_route_handler server ~meth:`PUT (route ()) (fun _ _ -> S.add_route_handler server ~meth:`PUT (route ()) (fun _ _ ->
@ -258,7 +259,7 @@ let add_vfs_ ~on_fs ~top ~config ~vfs:((module VFS : VFS) as vfs) ~prefix server
if config.download then if config.download then
S.add_route_handler server ~meth:`GET (route ()) (fun path req -> S.add_route_handler server ~meth:`GET (route ()) (fun path req ->
S._debug (fun k -> k "path=%S" path); Log.debug (fun k -> k "dir: download path=%S" path);
let mtime = let mtime =
lazy lazy
(match VFS.file_mtime path with (match VFS.file_mtime path with
@ -272,11 +273,11 @@ let add_vfs_ ~on_fs ~top ~config ~vfs:((module VFS : VFS) as vfs) ~prefix server
else if else if
S.Request.get_header req "If-None-Match" = Some (Lazy.force mtime) S.Request.get_header req "If-None-Match" = Some (Lazy.force mtime)
then ( then (
S._debug (fun k -> Log.debug (fun k ->
k "cached object %S (etag: %S)" path (Lazy.force mtime)); k "dir: cached object %S (etag: %S)" path (Lazy.force mtime));
S.Response.make_raw ~code:304 "" S.Response.make_raw ~code:304 ""
) else if VFS.is_directory path then ( ) else if VFS.is_directory path then (
S._debug (fun k -> k "list dir %S (topdir %S)" path VFS.descr); Log.debug (fun k -> k "dir: list dir %S (topdir %S)" path VFS.descr);
let parent = Filename.(dirname path) in let parent = Filename.(dirname path) in
let parent = let parent =
if Filename.basename path <> "." then if Filename.basename path <> "." then
@ -288,7 +289,7 @@ let add_vfs_ ~on_fs ~top ~config ~vfs:((module VFS : VFS) as vfs) ~prefix server
| (Index | Index_or_lists) when VFS.contains (path // "index.html") -> | (Index | Index_or_lists) when VFS.contains (path // "index.html") ->
(* redirect using path, not full path *) (* redirect using path, not full path *)
let new_path = "/" // prefix // path // "index.html" in let new_path = "/" // prefix // path // "index.html" in
S._debug (fun k -> k "redirect to `%s`" new_path); Log.debug (fun k -> k "dir: redirect to `%s`" new_path);
S.Response.make_void ~code:301 () S.Response.make_void ~code:301 ()
~headers:S.Headers.(empty |> set "location" new_path) ~headers:S.Headers.(empty |> set "location" new_path)
| Lists | Index_or_lists -> | Lists | Index_or_lists ->
@ -425,7 +426,7 @@ module Embedded_fs = struct
| _ -> None | _ -> None
let contains p = let contains p =
S._debug (fun k -> k "contains %S" p); Log.debug (fun k -> k "vfs: contains %S" p);
match find_ self p with match find_ self p with
| Some _ -> true | Some _ -> true
| None -> false | None -> false
@ -441,7 +442,7 @@ module Embedded_fs = struct
| _ -> failwith (Printf.sprintf "no such file: %S" p) | _ -> failwith (Printf.sprintf "no such file: %S" p)
let list_dir p = let list_dir p =
S._debug (fun k -> k "list dir %S" p); Log.debug (fun k -> k "vfs: list dir %S" p);
match find_ self p with match find_ self p with
| Some (Dir sub) -> | Some (Dir sub) ->
Str_map.fold (fun sub _ acc -> sub :: acc) sub.entries [] Str_map.fold (fun sub _ acc -> sub :: acc) sub.entries []

View file

@ -0,0 +1,6 @@
(* default: no logging *)
let info _ = ()
let debug _ = ()
let error _ = ()
let enable ~debug:_ () = ()

View file

@ -0,0 +1,16 @@
(* Use Logs *)
module Log = (val Logs.(src_log @@ Src.create "tiny_httpd"))
let info k = Log.info (fun fmt -> k (fun x -> fmt ?header:None ?tags:None x))
let debug k = Log.debug (fun fmt -> k (fun x -> fmt ?header:None ?tags:None x))
let error k = Log.err (fun fmt -> k (fun x -> fmt ?header:None ?tags:None x))
let setup ~debug () =
Logs.set_reporter @@ Logs.format_reporter ();
Logs.set_level ~all:true
(Some
(if debug then
Logs.Debug
else
Logs.Info))

10
src/Tiny_httpd_log.mli Normal file
View file

@ -0,0 +1,10 @@
(** Logging for tiny_httpd *)
val info : ((('a, Format.formatter, unit, unit) format4 -> 'a) -> unit) -> unit
val debug : ((('a, Format.formatter, unit, unit) format4 -> 'a) -> unit) -> unit
val error : ((('a, Format.formatter, unit, unit) format4 -> 'a) -> unit) -> unit
val setup : debug:bool -> unit -> unit
(** Setup and enable logging. This should only ever be used in executables,
not libraries.
@param debug if true, set logging to debug (otherwise info) *)

View file

@ -1,25 +1,11 @@
type buf = Tiny_httpd_buf.t type buf = Tiny_httpd_buf.t
type byte_stream = Tiny_httpd_stream.t type byte_stream = Tiny_httpd_stream.t
let _debug_on =
ref
(match String.trim @@ Sys.getenv "HTTP_DBG" with
| "" -> false
| _ -> true
| exception _ -> false)
let _enable_debug b = _debug_on := b
let _debug k =
if !_debug_on then
k (fun fmt ->
Printf.fprintf stdout "[http.thread %d]: " Thread.(id @@ self ());
Printf.kfprintf (fun oc -> Printf.fprintf oc "\n%!") stdout fmt)
module Buf = Tiny_httpd_buf module Buf = Tiny_httpd_buf
module Byte_stream = Tiny_httpd_stream module Byte_stream = Tiny_httpd_stream
module IO = Tiny_httpd_io module IO = Tiny_httpd_io
module Pool = Tiny_httpd_pool module Pool = Tiny_httpd_pool
module Log = Tiny_httpd_log
exception Bad_req of int * string exception Bad_req of int * string
@ -137,7 +123,7 @@ module Headers = struct
let parse_ ~buf (bs : byte_stream) : t = let parse_ ~buf (bs : byte_stream) : t =
let rec loop acc = let rec loop acc =
let line = Byte_stream.read_line ~buf bs in let line = Byte_stream.read_line ~buf bs in
_debug (fun k -> k "parsed header line %S" line); Log.debug (fun k -> k "parsed header line %S" line);
if line = "\r" then if line = "\r" then
acc acc
else ( else (
@ -225,11 +211,11 @@ module Request = struct
(* decode a "chunked" stream into a normal stream *) (* decode a "chunked" stream into a normal stream *)
let read_stream_chunked_ ?buf (bs : byte_stream) : byte_stream = let read_stream_chunked_ ?buf (bs : byte_stream) : byte_stream =
_debug (fun k -> k "body: start reading chunked stream..."); Log.debug (fun k -> k "body: start reading chunked stream...");
Byte_stream.read_chunked ?buf ~fail:(fun s -> Bad_req (400, s)) bs Byte_stream.read_chunked ?buf ~fail:(fun s -> Bad_req (400, s)) bs
let limit_body_size_ ~max_size (bs : byte_stream) : byte_stream = let limit_body_size_ ~max_size (bs : byte_stream) : byte_stream =
_debug (fun k -> k "limit size of body to max-size=%d" max_size); Log.debug (fun k -> k "limit size of body to max-size=%d" max_size);
Byte_stream.limit_size_to ~max_size ~close_rec:false bs Byte_stream.limit_size_to ~max_size ~close_rec:false bs
~too_big:(fun size -> ~too_big:(fun size ->
(* read too much *) (* read too much *)
@ -242,7 +228,7 @@ module Request = struct
(* read exactly [size] bytes from the stream *) (* read exactly [size] bytes from the stream *)
let read_exactly ~size (bs : byte_stream) : byte_stream = let read_exactly ~size (bs : byte_stream) : byte_stream =
_debug (fun k -> k "body: must read exactly %d bytes" size); Log.debug (fun k -> k "body: must read exactly %d bytes" size);
Byte_stream.read_exactly bs ~close_rec:false ~size ~too_short:(fun size -> Byte_stream.read_exactly bs ~close_rec:false ~size ~too_short:(fun size ->
bad_reqf 400 "body is too short by %d bytes" size) bad_reqf 400 "body is too short by %d bytes" size)
@ -260,11 +246,11 @@ module Request = struct
if version != 0 && version != 1 then raise Exit; if version != 0 && version != 1 then raise Exit;
meth, path, version meth, path, version
with _ -> with _ ->
_debug (fun k -> k "invalid request line: `%s`" line); Log.error (fun k -> k "invalid request line: `%s`" line);
raise (Bad_req (400, "Invalid request line")) raise (Bad_req (400, "Invalid request line"))
in in
let meth = Meth.of_string meth in let meth = Meth.of_string meth in
_debug (fun k -> k "got meth: %s, path %S" (Meth.to_string meth) path); Log.debug (fun k -> k "got meth: %s, path %S" (Meth.to_string meth) path);
let headers = Headers.parse_ ~buf bs in let headers = Headers.parse_ ~buf bs in
let host = let host =
match Headers.get "Host" headers with match Headers.get "Host" headers with
@ -463,7 +449,7 @@ module Response = struct
self.headers self.headers
in in
let self = { self with headers; body } in let self = { self with headers; body } in
_debug (fun k -> Log.debug (fun k ->
k "output response: %s" k "output response: %s"
(Format.asprintf "%a" pp { self with body = `String "<...>" })); (Format.asprintf "%a" pp { self with body = `String "<...>" }));
@ -872,6 +858,11 @@ module Unix_tcp_server_ = struct
mutable running: bool; (* TODO: use an atomic? *) mutable running: bool; (* TODO: use an atomic? *)
} }
let str_of_sockaddr = function
| Unix.ADDR_UNIX f -> f
| Unix.ADDR_INET (inet, port) ->
Printf.sprintf "%s:%d" (Unix.string_of_inet_addr inet) port
let to_tcp_server (self : t) : IO.TCP_server.builder = let to_tcp_server (self : t) : IO.TCP_server.builder =
{ {
IO.TCP_server.serve = IO.TCP_server.serve =
@ -923,6 +914,8 @@ module Unix_tcp_server_ = struct
(* how to handle a single client *) (* how to handle a single client *)
let handle_client_unix_ (client_sock : Unix.file_descr) let handle_client_unix_ (client_sock : Unix.file_descr)
(client_addr : Unix.sockaddr) : unit = (client_addr : Unix.sockaddr) : unit =
Log.info (fun k ->
k "serving new client on %s" (str_of_sockaddr client_addr));
Unix.(setsockopt_float client_sock SO_RCVTIMEO self.timeout); Unix.(setsockopt_float client_sock SO_RCVTIMEO self.timeout);
Unix.(setsockopt_float client_sock SO_SNDTIMEO self.timeout); Unix.(setsockopt_float client_sock SO_SNDTIMEO self.timeout);
let oc = let oc =
@ -930,11 +923,15 @@ module Unix_tcp_server_ = struct
in in
let ic = IO.Input.of_unix_fd client_sock in let ic = IO.Input.of_unix_fd client_sock in
handle.handle ~client_addr ic oc; handle.handle ~client_addr ic oc;
_debug (fun k -> k "done with client, exiting"); Log.info (fun k ->
k "done with client on %s, exiting"
@@ str_of_sockaddr client_addr);
(try Unix.close client_sock (try Unix.close client_sock
with e -> with e ->
_debug (fun k -> Log.error (fun k ->
k "error when closing sock: %s" (Printexc.to_string e))); k "error when closing sock for client %s: %s"
(str_of_sockaddr client_addr)
(Printexc.to_string e)));
() ()
in in
@ -963,7 +960,7 @@ module Unix_tcp_server_ = struct
-> ->
() ()
| exception e -> | exception e ->
_debug (fun k -> Log.error (fun k ->
k "Unix.accept or Thread.create raised an exception: %s" k "Unix.accept or Thread.create raised an exception: %s"
(Printexc.to_string e)) (Printexc.to_string e))
done; done;
@ -1030,7 +1027,7 @@ let client_handle_for (self : t) ~client_addr ic oc : unit =
let is = Byte_stream.of_input ~buf_size:self.buf_size ic in let is = Byte_stream.of_input ~buf_size:self.buf_size ic in
let continue = ref true in let continue = ref true in
while !continue && running self do while !continue && running self do
_debug (fun k -> k "read next request"); Log.debug (fun k -> k "read next request");
let (module B) = self.backend in let (module B) = self.backend in
match match
Request.parse_req_start ~client_addr ~get_time_s:B.get_time_s ~buf is Request.parse_req_start ~client_addr ~get_time_s:B.get_time_s ~buf is
@ -1042,7 +1039,8 @@ let client_handle_for (self : t) ~client_addr ic oc : unit =
(try Response.output_ ~buf:buf_res oc res with Sys_error _ -> ()); (try Response.output_ ~buf:buf_res oc res with Sys_error _ -> ());
continue := false continue := false
| Ok (Some req) -> | Ok (Some req) ->
_debug (fun k -> k "req: %s" (Format.asprintf "@[%a@]" Request.pp_ req)); Log.debug (fun k ->
k "parsed request: %s" (Format.asprintf "@[%a@]" Request.pp_ req));
if Request.close_after_req req then continue := false; if Request.close_after_req req then continue := false;
@ -1057,7 +1055,7 @@ let client_handle_for (self : t) ~client_addr ic oc : unit =
(* handle expect/continue *) (* handle expect/continue *)
(match Request.get_header ~f:String.trim req "Expect" with (match Request.get_header ~f:String.trim req "Expect" with
| Some "100-continue" -> | Some "100-continue" ->
_debug (fun k -> k "send back: 100 CONTINUE"); Log.debug (fun k -> k "send back: 100 CONTINUE");
Response.output_ ~buf:buf_res oc (Response.make_raw ~code:100 "") Response.output_ ~buf:buf_res oc (Response.make_raw ~code:100 "")
| Some s -> bad_reqf 417 "unknown expectation %s" s | Some s -> bad_reqf 417 "unknown expectation %s" s
| None -> ()); | None -> ());

View file

@ -67,8 +67,7 @@ module Request : sig
meth: Meth.t; (** HTTP method for this request. *) meth: Meth.t; (** HTTP method for this request. *)
host: string; host: string;
(** Host header, mandatory. It can also be found in {!headers}. *) (** Host header, mandatory. It can also be found in {!headers}. *)
client_addr: Unix.sockaddr; client_addr: Unix.sockaddr; (** Client address. Available since 0.14. *)
(** Client address. Available since 0.14. *)
headers: Headers.t; (** List of headers. *) headers: Headers.t; (** List of headers. *)
http_version: int * int; http_version: int * int;
(** HTTP version. This should be either [1, 0] or [1, 1]. *) (** HTTP version. This should be either [1, 0] or [1, 1]. *)
@ -667,12 +666,3 @@ val run_exn : ?after_init:(unit -> unit) -> t -> unit
(** [run_exn s] is like [run s] but re-raises an exception if the server exits (** [run_exn s] is like [run s] but re-raises an exception if the server exits
with an error. with an error.
@since 0.14 *) @since 0.14 *)
(**/**)
val _debug :
((('a, out_channel, unit, unit, unit, unit) format6 -> 'a) -> unit) -> unit
val _enable_debug : bool -> unit
(**/**)

View file

@ -2,6 +2,7 @@ module S = Tiny_httpd
module U = Tiny_httpd_util module U = Tiny_httpd_util
module D = Tiny_httpd_dir module D = Tiny_httpd_dir
module Pf = Printf module Pf = Printf
module Log = Tiny_httpd.Log
let serve ~config (dir : string) addr port j : _ result = let serve ~config (dir : string) addr port j : _ result =
let server = S.create ~max_connections:j ~addr ~port () in let server = S.create ~max_connections:j ~addr ~port () in
@ -39,7 +40,7 @@ let main () =
"--port", Set_int port, " port to listen on"; "--port", Set_int port, " port to listen on";
"-p", Set_int port, " alias to --port"; "-p", Set_int port, " alias to --port";
"--dir", Set_string dir_, " directory to serve (default: \".\")"; "--dir", Set_string dir_, " directory to serve (default: \".\")";
"--debug", Unit (fun () -> S._enable_debug true), " debug mode"; "--debug", Unit (Log.setup ~debug:true), " debug mode";
( "--upload", ( "--upload",
Unit (fun () -> config.upload <- true), Unit (fun () -> config.upload <- true),
" enable file uploading" ); " enable file uploading" );

View file

@ -2,9 +2,10 @@ module S = Tiny_httpd_server
module BS = Tiny_httpd_stream module BS = Tiny_httpd_stream
module W = Tiny_httpd_io.Writer module W = Tiny_httpd_io.Writer
module Out = Tiny_httpd_io.Output module Out = Tiny_httpd_io.Output
module Log = Tiny_httpd.Log
let decode_deflate_stream_ ~buf_size (is : S.byte_stream) : S.byte_stream = let decode_deflate_stream_ ~buf_size (is : S.byte_stream) : S.byte_stream =
S._debug (fun k -> k "wrap stream with deflate.decode"); Log.debug (fun k -> k "wrap stream with deflate.decode");
let zlib_str = Zlib.inflate_init false in let zlib_str = Zlib.inflate_init false in
let is_done = ref false in let is_done = ref false in
BS.make ~bs:(Bytes.create buf_size) BS.make ~bs:(Bytes.create buf_size)
@ -31,19 +32,19 @@ let decode_deflate_stream_ ~buf_size (is : S.byte_stream) : S.byte_stream =
self.off <- 0; self.off <- 0;
self.len <- used_out; self.len <- used_out;
if finished then is_done := true; if finished then is_done := true;
S._debug (fun k -> Log.debug (fun k ->
k "decode %d bytes as %d bytes from inflate (finished: %b)" k "decode %d bytes as %d bytes from inflate (finished: %b)"
used_in used_out finished) used_in used_out finished)
with Zlib.Error (e1, e2) -> with Zlib.Error (e1, e2) ->
S.Response.fail_raise ~code:400 S.Response.fail_raise ~code:400
"inflate: error during decompression:\n%s %s" e1 e2); "inflate: error during decompression:\n%s %s" e1 e2);
S._debug (fun k -> Log.debug (fun k ->
k "inflate: refill %d bytes into internal buf" self.len) k "inflate: refill %d bytes into internal buf" self.len)
)) ))
() ()
let encode_deflate_writer_ ~buf_size (w : W.t) : W.t = let encode_deflate_writer_ ~buf_size (w : W.t) : W.t =
S._debug (fun k -> k "wrap writer with deflate.encode"); Log.debug (fun k -> k "wrap writer with deflate.encode");
let zlib_str = Zlib.deflate_init 4 false in let zlib_str = Zlib.deflate_init 4 false in
let o_buf = Bytes.create buf_size in let o_buf = Bytes.create buf_size in
@ -170,7 +171,7 @@ let compress_resp_stream_ ~compress_above ~buf_size (req : _ S.Request.t)
match resp.body with match resp.body with
| `String s when String.length s > compress_above -> | `String s when String.length s > compress_above ->
(* big string, we compress *) (* big string, we compress *)
S._debug (fun k -> Log.debug (fun k ->
k "encode str response with deflate (size %d, threshold %d)" k "encode str response with deflate (size %d, threshold %d)"
(String.length s) compress_above); (String.length s) compress_above);
let body = encode_deflate_writer_ ~buf_size @@ W.of_string s in let body = encode_deflate_writer_ ~buf_size @@ W.of_string s in
@ -178,13 +179,13 @@ let compress_resp_stream_ ~compress_above ~buf_size (req : _ S.Request.t)
|> S.Response.update_headers update_headers |> S.Response.update_headers update_headers
|> S.Response.set_body (`Writer body) |> S.Response.set_body (`Writer body)
| `Stream str -> | `Stream str ->
S._debug (fun k -> k "encode stream response with deflate"); Log.debug (fun k -> k "encode stream response with deflate");
let w = BS.to_writer str in let w = BS.to_writer str in
resp resp
|> S.Response.update_headers update_headers |> S.Response.update_headers update_headers
|> S.Response.set_body (`Writer (encode_deflate_writer_ ~buf_size w)) |> S.Response.set_body (`Writer (encode_deflate_writer_ ~buf_size w))
| `Writer w -> | `Writer w ->
S._debug (fun k -> k "encode writer response with deflate"); Log.debug (fun k -> k "encode writer response with deflate");
resp resp
|> S.Response.update_headers update_headers |> S.Response.update_headers update_headers
|> S.Response.set_body (`Writer (encode_deflate_writer_ ~buf_size w)) |> S.Response.set_body (`Writer (encode_deflate_writer_ ~buf_size w))
@ -202,5 +203,5 @@ let middleware ?(compress_above = 16 * 1024) ?(buf_size = 16 * 1_024) () :
let setup ?compress_above ?buf_size server = let setup ?compress_above ?buf_size server =
let m = middleware ?compress_above ?buf_size () in let m = middleware ?compress_above ?buf_size () in
S._debug (fun k -> k "setup gzip support"); Log.info (fun k -> k "setup gzip middleware");
S.add_middleware ~stage:`Encoding server m S.add_middleware ~stage:`Encoding server m

View file

@ -1,13 +1,10 @@
(env
(_
(flags :standard -warn-error -a+8 -w +a-4-32-40-42-44-48-70 -color always -safe-string
-strict-sequence)))
(library (library
(name tiny_httpd) (name tiny_httpd)
(public_name tiny_httpd) (public_name tiny_httpd)
(libraries threads seq unix) (libraries threads seq unix
(select Tiny_httpd_log.ml from
(logs -> Tiny_httpd_log.logs.ml)
(-> Tiny_httpd_log.default.ml)))
(wrapped false)) (wrapped false))
(rule (rule

View file

@ -22,6 +22,7 @@ depends: [
"qcheck-core" {>= "0.9" & with-test} "qcheck-core" {>= "0.9" & with-test}
] ]
depopts: [ depopts: [
"logs"
"mtime" {>= "2.0"} "mtime" {>= "2.0"}
] ]
build: [ build: [