rustwebserverbinaryfilesrust-warp

Serving image files in dynamic directories in warp


I am writing a simple web server using warp. I'm having issues image files which are stored in 'dynamic' directories, i.e. the directories have a static prefix but might be renamed. I successfully resolved the correct file, e.g. "1/image.png" resolves to "1-dynamic-name/image.png". But I don't understand how I am able to return the binary file content to the client.

My current approach is the following (shortened for clarity):

Routing:

let dyn_image = warp::path("base").and(warp::path::param::<u32>())
    .and(warp::path::param::<String>()).and(warp::path::end())
    .and(warp::get()).and_then(dyn_image);
warp::serve(dyn_image).run(([0, 0, 0, 0], 8000)).await;

Resolving:

pub async fn dyn_image(idx: u32, image: String) -> Result<impl warp::Reply, Rejection> {
    let mut img_dir: PathBuf = ...
    // Resolving the dynamic directory
    if img_dir.exists() {
        // How can I now serve the image file back to the client?
        return Ok(warp::reply::?); // What's the correct reply?
    }
    Err(warp::reject())
}

I am struggling with the actual reply content. As far as I read the documentation, only reply::json and reply::html are implemented for a convenient response creation. But how is binary data handled? Do I need a stream, can I specify the file directly, like in warp::fs::file("..."), or do I read the entire file into a buffer? I also saw something like a ResponseBuilder?


Solution

  • The result return type you are returning Result<impl warp::Reply, Rejection> can be many different data types. For example, you can create a http::Response which contains the data of your file. Or even implement your own custom data type which sets the headers for you.

    use std::fs;
    use warp::{Filter, http::Response};
    
    return warp::any().map(|| {
        Response::builder()
            .header("Content-Type", "application/octet-stream")
            .body(fs::read(file_path).expect("Could not read file"))
    

    Code modified from warp::reply documentation. You probably need to read the file in as a byte stream as shown by std::fs::read. Standard error handling applies, the file should probably be read before building a Response so you can build a proper error response if the file is not readable.