Skip to content

Commit 20275c1

Browse files
committed
improve docs and opam, tidy up for 0.1; rename stream
1 parent 8bfcf36 commit 20275c1

File tree

5 files changed

+67
-63
lines changed

5 files changed

+67
-63
lines changed

src/Tiny_httpd.ml

Lines changed: 47 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
type stream = {
2-
is_fill_buf: unit -> (bytes * int * int);
3-
is_consume: int -> unit;
4-
is_close: unit -> unit;
1+
type byte_stream = {
2+
bs_fill_buf: unit -> (bytes * int * int);
3+
bs_consume: int -> unit;
4+
bs_close: unit -> unit;
55
}
66
(** A buffer input stream, with a view into the current buffer (or refill if empty),
77
and a function to consume [n] bytes *)
@@ -54,23 +54,23 @@ module Buf_ = struct
5454
x
5555
end
5656

57-
module Stream_ = struct
58-
type t = stream
57+
module Byte_stream = struct
58+
type t = byte_stream
5959

60-
let close self = self.is_close()
60+
let close self = self.bs_close()
6161

6262
let of_chan_ ~close ic : t =
6363
let i = ref 0 in
6464
let len = ref 0 in
6565
let buf = Bytes.make 4096 ' ' in
66-
{ is_fill_buf=(fun () ->
66+
{ bs_fill_buf=(fun () ->
6767
if !i >= !len then (
6868
i := 0;
6969
len := input ic buf 0 (Bytes.length buf);
7070
);
7171
buf, !i,!len - !i);
72-
is_consume=(fun n -> i := !i + n);
73-
is_close=(fun () -> close ic)
72+
bs_consume=(fun n -> i := !i + n);
73+
bs_close=(fun () -> close ic)
7474
}
7575

7676
let of_chan = of_chan_ ~close:close_in
@@ -85,9 +85,9 @@ module Stream_ = struct
8585
)
8686
in
8787
let i = ref i in
88-
{ is_fill_buf=(fun () -> s, !i, !len);
89-
is_close=(fun () -> ());
90-
is_consume=(fun n -> i := !i + n; len := !len - n);
88+
{ bs_fill_buf=(fun () -> s, !i, !len);
89+
bs_close=(fun () -> ());
90+
bs_consume=(fun n -> i := !i + n; len := !len - n);
9191
}
9292

9393
let with_file file f =
@@ -102,10 +102,10 @@ module Stream_ = struct
102102

103103
(* Read as much as possible into [buf]. *)
104104
let read_into_buf (self:t) (buf:Buf_.t) : int =
105-
let s, i, len = self.is_fill_buf () in
105+
let s, i, len = self.bs_fill_buf () in
106106
if len > 0 then (
107107
Buf_.add_bytes buf s i len;
108-
self.is_consume len;
108+
self.bs_consume len;
109109
);
110110
len
111111

@@ -125,11 +125,11 @@ module Stream_ = struct
125125
let offset = ref 0 in
126126
while !offset < n do
127127
let n_read =
128-
let s, i, len = self.is_fill_buf () in
128+
let s, i, len = self.bs_fill_buf () in
129129
let n_read = min len (n- !offset) in
130130
Bytes.blit s i bytes !offset n_read;
131131
offset := !offset + n_read;
132-
self.is_consume n_read;
132+
self.bs_consume n_read;
133133
n_read
134134
in
135135
if n_read=0 then too_short();
@@ -140,7 +140,7 @@ module Stream_ = struct
140140
Buf_.clear buf;
141141
let continue = ref true in
142142
while !continue do
143-
let s, i, len = self.is_fill_buf () in
143+
let s, i, len = self.bs_fill_buf () in
144144
if len=0 then continue := false;
145145
let j = ref i in
146146
while !j < i+len && Bytes.get s !j <> '\n' do
@@ -149,11 +149,11 @@ module Stream_ = struct
149149
if !j-i < len then (
150150
assert (Bytes.get s !j = '\n');
151151
Buf_.add_bytes buf s i (!j-i); (* without \n *)
152-
self.is_consume (!j-i+1); (* remove \n *)
152+
self.bs_consume (!j-i+1); (* remove \n *)
153153
continue := false
154154
) else (
155155
Buf_.add_bytes buf s i len;
156-
self.is_consume len;
156+
self.bs_consume len;
157157
)
158158
done
159159

@@ -237,9 +237,9 @@ module Headers = struct
237237
let pp_pair out (k,v) = Format.fprintf out "@[<h>%s: %s@]" k v in
238238
Format.fprintf out "@[<v>%a@]" (Format.pp_print_list pp_pair) l
239239

240-
let parse_ ~buf (is:stream) : t =
240+
let parse_ ~buf (bs:byte_stream) : t =
241241
let rec loop acc =
242-
let line = Stream_.read_line ~buf is in
242+
let line = Byte_stream.read_line ~buf bs in
243243
_debug (fun k->k "parsed header line %S" line);
244244
if line = "\r" then (
245245
acc
@@ -283,16 +283,16 @@ module Request = struct
283283
(Meth.to_string self.meth) self.host Headers.pp self.headers
284284
self.path self.body
285285

286-
let read_body_exact (is:stream) (n:int) : string =
286+
let read_body_exact (bs:byte_stream) (n:int) : string =
287287
let bytes = Bytes.make n ' ' in
288-
Stream_.read_exactly_ is bytes n
288+
Byte_stream.read_exactly_ bs bytes n
289289
~too_short:(fun () -> bad_reqf 400 "body is too short");
290290
Bytes.unsafe_to_string bytes
291291

292292
(* decode a "chunked" stream into a normal stream *)
293-
let read_stream_chunked_ ?(buf=Buf_.create()) (is:stream) : stream =
293+
let read_stream_chunked_ ?(buf=Buf_.create()) (bs:byte_stream) : byte_stream =
294294
let read_next_chunk_len () : int =
295-
let line = Stream_.read_line ~buf is in
295+
let line = Byte_stream.read_line ~buf bs in
296296
(* parse chunk length, ignore extensions *)
297297
let chunk_size = (
298298
if String.trim line = "" then 0
@@ -307,7 +307,7 @@ module Request = struct
307307
let offset = ref 0 in
308308
let len = ref 0 in
309309
let chunk_size = ref 0 in
310-
{ is_fill_buf=
310+
{ bs_fill_buf=
311311
(fun () ->
312312
(* do we need to refill? *)
313313
if !offset >= !len then (
@@ -319,9 +319,9 @@ module Request = struct
319319
if !chunk_size > 0 then (
320320
(* read the whole chunk, or [Bytes.length bytes] of it *)
321321
let to_read = min !chunk_size (Bytes.length bytes) in
322-
Stream_.read_exactly_
322+
Byte_stream.read_exactly_
323323
~too_short:(fun () -> bad_reqf 400 "chunk is too short")
324-
is bytes to_read;
324+
bs bytes to_read;
325325
len := to_read;
326326
chunk_size := !chunk_size - to_read;
327327
) else (
@@ -330,17 +330,17 @@ module Request = struct
330330
);
331331
bytes, !offset, !len
332332
);
333-
is_consume=(fun n -> offset := !offset + n);
334-
is_close=(fun () -> Stream_.close is);
333+
bs_consume=(fun n -> offset := !offset + n);
334+
bs_close=(fun () -> Byte_stream.close bs);
335335
}
336336

337-
let read_body_chunked ~tr_stream ~buf ~size:max_size (is:stream) : string =
337+
let read_body_chunked ~tr_stream ~buf ~size:max_size (bs:byte_stream) : string =
338338
_debug (fun k->k "read body with chunked encoding (max-size: %d)" max_size);
339-
let is = tr_stream @@ read_stream_chunked_ ~buf is in
339+
let is = tr_stream @@ read_stream_chunked_ ~buf bs in
340340
let buf_res = Buf_.create() in (* store the accumulated chunks *)
341341
(* TODO: extract this as a function [read_all_up_to ~max_size is]? *)
342342
let rec read_chunks () =
343-
let n = Stream_.read_into_buf is buf_res in
343+
let n = Byte_stream.read_into_buf is buf_res in
344344
if n = 0 then (
345345
Buf_.contents buf_res (* done *)
346346
) else (
@@ -356,16 +356,16 @@ module Request = struct
356356
read_chunks()
357357

358358
(* parse request, but not body (yet) *)
359-
let parse_req_start ~buf (is:stream) : unit t option resp_result =
359+
let parse_req_start ~buf (bs:byte_stream) : unit t option resp_result =
360360
try
361-
let line = Stream_.read_line ~buf is in
361+
let line = Byte_stream.read_line ~buf bs in
362362
let meth, path =
363363
try Scanf.sscanf line "%s %s HTTP/1.1\r" (fun x y->x,y)
364364
with _ -> raise (Bad_req (400, "Invalid request line"))
365365
in
366366
let meth = Meth.of_string meth in
367367
_debug (fun k->k "got meth: %s, path %S" (Meth.to_string meth) path);
368-
let headers = Headers.parse_ ~buf is in
368+
let headers = Headers.parse_ ~buf bs in
369369
let host =
370370
try List.assoc "Host" headers
371371
with Not_found -> bad_reqf 400 "No 'Host' header in request"
@@ -379,7 +379,7 @@ module Request = struct
379379

380380
(* parse body, given the headers.
381381
@param tr_stream a transformation of the input stream. *)
382-
let parse_body_ ~tr_stream ~buf (req:stream t) : string t resp_result =
382+
let parse_body_ ~tr_stream ~buf (req:byte_stream t) : string t resp_result =
383383
try
384384
let size =
385385
match List.assoc "Content-Length" req.headers |> int_of_string with
@@ -401,17 +401,17 @@ module Request = struct
401401
| e ->
402402
Error (400, Printexc.to_string e)
403403

404-
let read_body_full (self:stream t) : string t =
404+
let read_body_full (self:byte_stream t) : string t =
405405
try
406-
let body = Stream_.read_all self.body in
406+
let body = Byte_stream.read_all self.body in
407407
{ self with body }
408408
with
409409
| Bad_req _ as e -> raise e
410410
| e -> bad_reqf 500 "failed to read body: %s" (Printexc.to_string e)
411411
end
412412

413413
module Response = struct
414-
type body = [`String of string | `Stream of stream]
414+
type body = [`String of string | `Stream of byte_stream]
415415
type t = {
416416
code: Response_code.t;
417417
headers: Headers.t;
@@ -457,14 +457,14 @@ module Response = struct
457457
self.code Headers.pp self.headers pp_body self.body
458458

459459
(* print a stream as a series of chunks *)
460-
let output_stream_chunked_ (oc:out_channel) (str:stream) : unit =
460+
let output_stream_chunked_ (oc:out_channel) (str:byte_stream) : unit =
461461
let continue = ref true in
462462
while !continue do
463463
(* next chunk *)
464-
let s, i, len = str.is_fill_buf () in
464+
let s, i, len = str.bs_fill_buf () in
465465
Printf.fprintf oc "%x\r\n" len;
466466
output oc s i len;
467-
str.is_consume len;
467+
str.bs_consume len;
468468
if len = 0 then (
469469
continue := false;
470470
);
@@ -523,7 +523,8 @@ type t = {
523523
masksigpipe: bool;
524524
mutable handler: (string Request.t -> Response.t);
525525
mutable path_handlers : (unit Request.t -> cb_path_handler resp_result option) list;
526-
mutable cb_decode_req: (unit Request.t -> (unit Request.t * (stream -> stream)) option) list;
526+
mutable cb_decode_req:
527+
(unit Request.t -> (unit Request.t * (byte_stream -> byte_stream)) option) list;
527528
mutable cb_encode_resp: (string Request.t -> Response.t -> Response.t option) list;
528529
mutable running: bool;
529530
}
@@ -583,7 +584,7 @@ let handle_client_ (self:t) (client_sock:Unix.file_descr) : unit =
583584
let ic = Unix.in_channel_of_descr client_sock in
584585
let oc = Unix.out_channel_of_descr client_sock in
585586
let buf = Buf_.create() in
586-
let is = Stream_.of_chan ic in
587+
let is = Byte_stream.of_chan ic in
587588
let continue = ref true in
588589
while !continue && self.running do
589590
_debug (fun k->k "read next request");

src/Tiny_httpd.mli

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,14 @@
1111
features by declaring a few endpoints, including one for uploading files:
1212
1313
{[
14+
module S = Tiny_httpd
1415
1516
let () =
1617
let server = S.create () in
1718
(* say hello *)
1819
S.add_path_handler ~meth:`GET server
19-
"/hello/%s@/" (fun name _req -> S.Response.make_string (Ok ("hello " ^name ^"!\n")));
20+
"/hello/%s@/" (fun name _req ->
21+
S.Response.make_string (Ok ("hello " ^name ^"!\n")));
2022
(* echo request *)
2123
S.add_path_handler server
2224
"/echo" (fun req -> S.Response.make_string
@@ -84,24 +86,24 @@ end
8486
Streams are used to represent a series of bytes that can arrive progressively.
8587
For example, an uploaded file will be sent as a series of chunks. *)
8688

87-
type stream = {
88-
is_fill_buf: unit -> (bytes * int * int);
89+
type byte_stream = {
90+
bs_fill_buf: unit -> (bytes * int * int);
8991
(** See the current slice of the internal buffer as [bytes, i, len],
9092
where the slice is [bytes[i] .. [bytes[i+len-1]]].
9193
Can block to refill the buffer if there is currently no content.
9294
If [len=0] then there is no more data. *)
93-
is_consume: int -> unit;
95+
bs_consume: int -> unit;
9496
(** Consume n bytes from the buffer. This should only be called with [n <= len]
9597
after a call to [is_fill_buf] that returns a slice of length [len]. *)
96-
is_close: unit -> unit;
98+
bs_close: unit -> unit;
9799
(** Close the stream. *)
98100
}
99101
(** A buffered stream, with a view into the current buffer (or refill if empty),
100102
and a function to consume [n] bytes.
101-
See {!Stream_} for more details. *)
103+
See {!Byte_stream} for more details. *)
102104

103-
module Stream_ : sig
104-
type t = stream
105+
module Byte_stream : sig
106+
type t = byte_stream
105107

106108
val close : t -> unit
107109

@@ -218,7 +220,7 @@ module Request : sig
218220
val body : 'b t -> 'b
219221
(** Request body, possibly empty. *)
220222

221-
val read_body_full : stream t -> string t
223+
val read_body_full : byte_stream t -> string t
222224
(** Read the whole body into a string. Potentially blocking. *)
223225
end
224226

@@ -244,7 +246,7 @@ end
244246
(** {2 Response} *)
245247

246248
module Response : sig
247-
type body = [`String of string | `Stream of stream]
249+
type body = [`String of string | `Stream of byte_stream]
248250
(** Body of a response, either as a simple string,
249251
or a stream of bytes. *)
250252

@@ -266,7 +268,7 @@ module Response : sig
266268
val make_raw_stream :
267269
?headers:Headers.t ->
268270
code:Response_code.t ->
269-
stream ->
271+
byte_stream ->
270272
t
271273
(** Same as {!make_raw} but with a stream body. The body will be sent with
272274
the chunked transfer-encoding. *)
@@ -288,7 +290,7 @@ module Response : sig
288290

289291
val make_stream :
290292
?headers:Headers.t ->
291-
(stream, Response_code.t * string) result -> t
293+
(byte_stream, Response_code.t * string) result -> t
292294
(** Same as {!make} but with a stream body. *)
293295

294296
val fail : ?headers:Headers.t -> code:int ->
@@ -346,7 +348,7 @@ val port : t -> int
346348

347349
val add_decode_request_cb :
348350
t ->
349-
(unit Request.t -> (unit Request.t * (stream -> stream)) option) -> unit
351+
(unit Request.t -> (unit Request.t * (byte_stream -> byte_stream)) option) -> unit
350352
(** Add a callback for every request.
351353
The callback can provide a stream transformer and a new request (with
352354
modified headers, typically).
@@ -378,7 +380,7 @@ val add_path_handler :
378380
'b, 'c -> string Request.t -> Response.t, 'a -> 'd, 'd) format6 ->
379381
'c -> unit
380382
(** [add_path_handler server "/some/path/%s@/%d/" f]
381-
calls [f request "foo" 42 ()] when a request with path "some/path/foo/42/"
383+
calls [f "foo" 42 request] when a request with path "some/path/foo/42/"
382384
is received.
383385
384386
This uses {!Scanf}'s splitting, which has some gotchas (in particular,

src/bin/dune

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@
44
(public_name http_of_dir)
55
(package tiny_httpd)
66
(flags :standard -warn-error -3)
7-
(libraries tiny_httpd str))
7+
(libraries tiny_httpd))

src/bin/http_of_dir.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ let serve ~config (dir:string) : _ result =
140140
let ic = open_in full_path in
141141
S.Response.make_raw_stream
142142
~headers:["Etag", Lazy.force mtime]
143-
~code:200 (S.Stream_.of_chan ic)
143+
~code:200 (S.Byte_stream.of_chan ic)
144144
with e ->
145145
S.Response.fail ~code:500 "error while reading file: %s" (Printexc.to_string e)
146146
));

tiny_httpd.opam

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ version: "0.1"
33
authors: ["Simon Cruanes"]
44
maintainer: "[email protected]"
55
license: "MIT"
6-
description: "Minimal HTTP server using good old threads"
6+
synopsis: "Minimal HTTP server using good old threads"
77
build: [
88
["dune" "build" "@install" "-p" name "-j" jobs]
99
["dune" "build" "@doc" "-p" name] {with-doc}
@@ -20,3 +20,4 @@ homepage: "https://github.com/c-cube/tiny_httpd/"
2020
doc: "https://c-cube.github.io/tiny_httpd/"
2121
bug-reports: "https://github.com/c-cube/tiny_httpd/issues"
2222
dev-repo: "git+https://github.com/c-cube/tiny_httpd.git"
23+
post-messages: "tiny http server, with blocking IOs. Also ships with a `http_of_dir` program."

0 commit comments

Comments
 (0)