FlashSystems / tokio-fastcgi

Async FastCGI handler library for Tokio.rs
Other
4 stars 1 forks source link

Question on return type from request.process callback #2

Closed aaronriekenberg closed 2 years ago

aaronriekenberg commented 2 years ago

I am porting a small go fastcgi app to rust and using your library: https://github.com/aaronriekenberg/rust-fastcgi

Thank you for creating a nice library - this has been a fun exercise to learn and practice rust a bit. 😄

One question:

Here in the apiserver example you use unwrap(): https://github.com/FlashSystems/tokio-fastcgi/blob/master/examples/apiserver.rs#L298

                                                  if let Err(err) = request.process(|request| async move {
                            process_request(req_store.clone(), request).await.unwrap()
                        }).await {
                            // This is the error handler that is called if the process call returns an error.
                            println!("Processing request failed: {}", err);
                        }

Suppose process_request(...).await returns an error - for example if request.get_stdout().write() returns a tokio_fastcgi::Error. Then I think the unwrap() here will cause a panic.

Is it possible to change the return type of the request.process() callback so that this is possible? Perhaps I am missing a way to do this - this does not seem to compile now:

                                                  if let Err(err) = request.process(|request| async move {
                            process_request(req_store.clone(), request).await
                        }).await {
                            // This is the error handler that is called if the process call returns an error.
                            println!("Processing request failed: {}", err);
                        }

Thank you!

FlashSystems commented 2 years ago

The root of this problem is, that FastCGI is a faster way to call CGI programs. And CGI programs had only one way to communicate an error back to the web-server: Return codes. Therefore the process() method accepts only results that it can communicate back to the web-server. The FastCGI spec only knows the following results:

In my own tokio-fastcgi application I've implemented a function that takes the result of the request processing and maps it to a RequestResult. Errors are logged and the result code is set to 1500. I've decided that the result code is the HTTP error code I would send + 1000. But this is just my convention.

fn map_request_result(result: Result<RequestResult, impl Error>) -> RequestResult {
    match result {
        Ok(request_result) => request_result,
        Err(err) => {
            log::error!("Error processing request: {}", err);
            RequestResult::Complete(1500)
        }
    }
}

Your call to process_request would then look like this:

map_request_result(send_response(request, response).await)

You could get fancy and try to implement some automatic conversion using the From trait, but I think a simple mapping function is clean and easy to comprehend.

aaronriekenberg commented 2 years ago

Thanks for the explanation. Will close this issue.