diff --git a/lib/Cro/HTTP/BodySerializers.pm6 b/lib/Cro/HTTP/BodySerializers.pm6 index 1f819a41..855c323f 100644 --- a/lib/Cro/HTTP/BodySerializers.pm6 +++ b/lib/Cro/HTTP/BodySerializers.pm6 @@ -55,7 +55,8 @@ class Cro::HTTP::BodySerializer::SupplyFallback does Cro::HTTP::BodySerializer { $body ~~ Supply } - method serialize(Cro::HTTP::Message $message, $body --> Supply) { + method serialize(Cro::HTTP::Message $message, $body, Int :$content_length --> Supply) { + self!set-content-length($message, $content_length) if $content_length; supply { whenever $body -> $chunk { unless $chunk ~~ Blob { diff --git a/lib/Cro/HTTP/Router.pm6 b/lib/Cro/HTTP/Router.pm6 index f66dda7b..a40441ca 100644 --- a/lib/Cro/HTTP/Router.pm6 +++ b/lib/Cro/HTTP/Router.pm6 @@ -829,7 +829,7 @@ module Cro::HTTP::Router { #| Specify content to be sent as a response, passing a content type and the #| body. The body will be serialized using a body serializer. If no request #| status was set, it will be set to 200 OK. - multi content(Str $content-type, $body, :$enc = $body ~~ Str ?? 'utf-8' !! Nil --> Nil) { + multi content(Str $content-type, $body, :$enc = $body ~~ Str ?? 'utf-8' !! Nil, :$content_length --> Nil) { my $resp = $*CRO-ROUTER-RESPONSE // die X::Cro::HTTP::Router::OnlyInHandler.new(:what); $resp.status //= 200; @@ -839,6 +839,9 @@ module Cro::HTTP::Router { else { $resp.append-header('Content-type', $content-type); } + + $resp.append-header('content-length', $content_length) if $content_length; + $resp.set-body($body); } @@ -1180,7 +1183,7 @@ module Cro::HTTP::Router { #| the first argument specifies a base path, and the remaining positional #| arguments are treated as path segments. However, it is not possible to #| reach a path above the base. - sub static(IO() $base, *@path, :$mime-types, :@indexes) is export { + sub static(IO() $base, *@path, :$mime-types, :@indexes, Int :$chunk_size) is export { my $resp = $*CRO-ROUTER-RESPONSE // die X::Cro::HTTP::Router::OnlyInHandler.new(:what); @@ -1196,14 +1199,24 @@ module Cro::HTTP::Router { for @indexes { my $index = $path.add($_); if $index.e { - content get-mime-or-default($index.extension, %fallback), slurp($index, :bin); - return; + if $chunk_size.defined { + content get-mime-or-default($index.extension, %fallback), $index.IO.open(:bin).Supply(size => $chunk_size), content_length => $index.IO.s; + return; + } else { + content get-mime-or-default($index.extension, %fallback), slurp($index, :bin); + return; + } } } $resp.status = 404; return; } else { - content get-mime-or-default($path.extension, %fallback), slurp($path, :bin); + if $chunk_size.defined { + content get-mime-or-default($path.extension, %fallback), $path.IO.open(:bin).Supply(size => $chunk_size), content_length => $path.IO.s; + } else { + content get-mime-or-default($path.extension, %fallback), slurp($path, :bin); + } + } } else { $resp.status = 404; diff --git a/t/http-router.t b/t/http-router.t index 3020c3f6..5f4c2915 100644 --- a/t/http-router.t +++ b/t/http-router.t @@ -1910,6 +1910,9 @@ throws-like { bad-request }, X::Cro::HTTP::Router::OnlyInHandler, what => 'bad-r 'html' => 'text/html' } } + get -> 'chunks' { + static 't/samples/', :indexes(['index.xhtml']) , :3chunk_size; + } } my $source = Supplier.new; my $responses = $app.transformer($source.Supply).Channel; @@ -1918,6 +1921,7 @@ throws-like { bad-request }, X::Cro::HTTP::Router::OnlyInHandler, what => 'bad-r given $responses.receive -> $r { like body-text($r), rx{ 'Extended' \n }, 'Get value from index'; is $r.status, 200, 'Static sets correct status code'; + is $r.header('Content-length'), 22, 'Content-length for static served files'; } $req = Cro::HTTP::Request.new(method => 'GET', target => '/index-plain'); @@ -1946,6 +1950,13 @@ throws-like { bad-request }, X::Cro::HTTP::Router::OnlyInHandler, what => 'bad-r is $r.status, 200, 'Indexes with mime-types returns good status'; is $r.header('Content-Type'), 'text/html', 'Indexes with mime-types returns proper content-type'; } + + $req = Cro::HTTP::Request.new(method => 'GET', target => '/chunks'); + $source.emit($req); + given $responses.receive -> $r { + like body-text($r), rx{ 'Extended' \n }, 'Get index.xhtml as chunks'; + is $r.header('Content-length'), 22, 'Content-length for as chunks served files'; + } } {