lilydocs
HTTP APIWebSocketConsumer
Techniques2 min read

Serving files and streaming

Expose a file root over HTTP or send application-produced bytes as a lazy response.

Use StaticFileMount to serve files from a disk root, and StreamingResponse to send byte chunks produced by the application.

Static file mount#

Create the mount once in the controller constructor. The directory must exist before build:

Controller constructor snippet
let mount = StaticFileMount::new("./public", "/files/public").await
    .map_err(ControllerInitError::invalid_configuration)?;
Ok(Self { mount })

The controller retains a mount: StaticFileMount field. Explicitly add the route under the /files base path:

Controller action snippet
#[get("/public/*path")]
async fn public_file(&self, request: &mut Request)
    -> Result<StaticFileResponse, HttpApiError>
{
    Ok(self.mount.serve(request).await?)
}

public/report.txt is served at /files/public/report.txt. GET/HEAD, conditional ETag/Last-Modified, single ranges, MIME, caching, and root-boundary behavior are part of this response path. The default symlink policy is deny.

Byte streaming#

Add futures = "0.3". Import std::convert::Infallible and the facade's streaming, Bytes, and StreamingResponse:

Controller action snippet
#[get("/export")]
async fn export(&self) -> StreamingResponse {
    let source = futures::stream::iter([
        Ok::<_, Infallible>(Bytes::from_static(b"{\"id\":1}\n")),
        Ok(Bytes::from_static(b"{\"id\":2}\n")),
    ]);
    streaming(source)
        .content_type("application/x-ndjson")
        .max_chunk_bytes(1024)
}

The response produces two NDJSON lines. The complete controller example includes the imports and mount field together.

Resource and time limits#

A lazy producer can run after the handler returns. A middleware's normal return does not mean every byte has been delivered to the client. The request scope closes in coordination with termination of the associated resources.

The default stream-item limit is 64 KiB. Chunk and deadline limits still apply even when the total stream-byte limit is None. The stream is subject to the request deadline that starts at admission. The producer must respond appropriately when cancellation arrives.

Sources for this page v0.1.0

This guide is based on the reviewed framework commit.

QUICK START
Documentation
Source code