Merge pull request #87 from c-cube/simon/fix-chunk-2024-06-18

fix chunking reading
This commit is contained in:
Simon Cruanes 2024-06-20 11:52:08 -04:00 committed by GitHub
commit 0b4c28264c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 59 additions and 4 deletions

View file

@ -9,6 +9,9 @@ build:
test:
@dune runtest --no-buffer --force $(OPTS)
test-autopromote:
@dune runtest --no-buffer --force $(OPTS) --auto-promote
clean:
@dune clean

View file

@ -348,7 +348,14 @@ module Input = struct
method private refill (slice : Slice.t) : unit =
if !chunk_size = 0 && not !eof then (
chunk_size := read_next_chunk_len ();
if !chunk_size = 0 then eof := true (* stream is finished *)
if !chunk_size = 0 then (
(* stream is finished, consume trailing \r\n *)
eof := true;
let line = read_line_using ~buf:line_buf ic in
if String.trim line <> "" then
raise
(fail (spf "expected \\r\\n to follow last chunk, got %S" line))
)
);
slice.off <- 0;
slice.len <- 0;

View file

@ -50,7 +50,7 @@ test_out.txt
</html>
hello
world
ykjNycnnKs8vyknhAgAAAP//AwA=
ykjNycnnKs8vyknhAgAAAP//
<html>
<head>

View file

@ -15,7 +15,10 @@ sleep 0.1
curl -N "http://localhost:${PORT}/vfs/a.txt" --max-time 5
sleep 0.1
curl -N "http://localhost:${PORT}/vfs/a.txt" -H 'accept-encoding: deflate' --max-time 5 | base64
# NOTE: the sed is there because of a timing/deflate non determinism. Both strings
# decompress to the same "hello\nworld\n" but which one is picked depends on
# the machine/library/… ?? but both are valid.
curl -N "http://localhost:${PORT}/vfs/a.txt" -H 'accept-encoding: deflate' --max-time 5 | base64 | sed 's+ykjNycnnKs8vyknhAgAAAP//AwA=+ykjNycnnKs8vyknhAgAAAP//+'
sleep 0.1
curl -N "http://localhost:${PORT}/vfs/sub/yolo.html" --max-time 5

View file

@ -1,5 +1,5 @@
(tests
(names t_util t_buf t_server)
(names t_util t_buf t_server t_io)
(package tiny_httpd)
(libraries tiny_httpd.core qcheck-core qcheck-core.runner test_util))

42
tests/unit/t_io.ml Normal file
View file

@ -0,0 +1,42 @@
open Test_util
open Tiny_httpd_core.IO
let spf = Printf.sprintf
(* one chunk *)
let () =
let io = Input.of_string "5\r\nhello\r\n0\r\n\r\nARGH" in
let str =
io
|> Input.read_chunked ~bytes:(Bytes.create 4) ~fail:failwith
|> Input.read_all_using ~buf:(Buf.create ())
in
assert_eq ~to_string:(spf "%S") "hello" str
(* two chunks *)
let () =
let io = Input.of_string "5\r\nhello\r\n6\r\n world\r\n0\r\n\r\nARGH" in
let str =
io
|> Input.read_chunked ~bytes:(Bytes.create 4) ~fail:failwith
|> Input.read_all_using ~buf:(Buf.create ())
in
assert_eq ~to_string:(spf "%S") "hello world" str;
let str_rest = io |> Input.read_all_using ~buf:(Buf.create ()) in
assert_eq ~to_string:(spf "%S") "ARGH" str_rest;
()
(* two chunks *)
let () =
let io = Input.of_string "10\r\n{\"poCheck\":true}\r\n0\r\n\r\n" in
let str =
io
|> Input.read_chunked ~bytes:(Bytes.create 4) ~fail:failwith
|> Input.read_all_using ~buf:(Buf.create ())
in
assert_eq ~to_string:(spf "%S") {|{"poCheck":true}|} str;
let str_rest = io |> Input.read_all_using ~buf:(Buf.create ()) in
assert_eq ~to_string:(spf "%S") "" str_rest;
()