How to read files correctly?

I have set up an actix web server to serve some files, the headers are necessary. For example on of the services:

fn open(x: PathBuf) -> String {
    fs::read_to_string(x).expect("Something went wrong")
}

#[get("/mithics.pck")]
async fn mithics_pck() -> impl Responder {
    let mut file = PathBuf::new();
    file.push("content/mithics.pck");
    HttpResponse::Ok()
        .append_header(("Cross-Origin-Opener-Policy", "same-origin"))
        .append_header(("Cross-Origin-Embedder-Policy", "credentialless"))
        .body(open(file))
}

The code compiles but when a client makes a request, an os error ocurrs despite the files being there.

Edit: the error message is the following just multiple times:

thread 'actix-rt|system:0|arbiter:0' panicked at src/main.rs:9:27:
Something went wrong: Error { kind: InvalidData, message: "stream did not contain valid UTF-8" }
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
thread 'actix-rt|system:0|arbiter:0' panicked at src/main.rs:52:14:
failed_to_read_file: Error { kind: InvalidData, message: "stream did not contain valid UTF-8" }

Care to post the error message or are we supposed to guess?

1 Like

So, the problem is that in open, you read the contents of the file into a String. In Rust, the String type is always a sequence of bytes in UTF-8 encoding and it will check this on construction. String in std::string - Rust. This means it won't work on files containing binary data.

You can avoid the error by using fs::read to get a Vec<u8>. read in std::fs - Rust. You should be able to pass it into send without much difficulty.

Someone more familiar with actix can tell you how to stream the file contents directly without reading it into memory first.

4 Likes

I believe I can tell you the reason that you get the error message multiple times even though it's a single request: Since you do .expect() in your open fn, it panics. But actix thinks that if there is a panic in a handler, it should be retried, and does that a bunch of times.

If you instead lets open return a Result, you can let mithics_pck handle that by returning a HttpResponse::InternalServerError(), and then the error only happens once per response (but then you don't have a panic message in the log, so in that case you should also print an error message to server log).

3 Likes

Thanks, I'll probably do this now

This worked thanks

Ok, I tried it but I have no idea what the error type of open should be